From 871db25ca305f77f1783bc619ae4ad60e3fe8d77 Mon Sep 17 00:00:00 2001 From: exterlulz Date: Fri, 20 Aug 2010 16:39:39 +0200 Subject: [PATCH] first commit --- .gitignore | 4 + About.xib | 1166 ++++++++++++++++ English.lproj/InfoPlist.strings | 2 + English.lproj/MainMenu.xib | 2568 ++++++++++++++++++++++++++++++++++++ English.lproj/Preferences.xib | 1933 +++++++++++++++++++++++++++ English.lproj/kokogems.html | 242 ++++ kokogems-Info.plist | 32 + kokogems.xcodeproj/project.pbxproj | 407 ++++++ kokogems_Prefix.pch | 7 + main.m | 5 + resources/background.png | Bin 0 -> 3351 bytes resources/continue.png | Bin 0 -> 188 bytes resources/cross.png | Bin 0 -> 1317 bytes resources/gpl2.licence.txt | 340 +++++ resources/icon.icns | Bin 0 -> 40920 bytes resources/movehint.png | Bin 0 -> 1522 bytes resources/mute.png | Bin 0 -> 511 bytes resources/old/1gem.png | Bin 0 -> 2312 bytes resources/old/2gem.png | Bin 0 -> 1126 bytes resources/old/3gem.png | Bin 0 -> 2369 bytes resources/old/4gem.png | Bin 0 -> 2134 bytes resources/old/5gem.png | Bin 0 -> 2413 bytes resources/old/6gem.png | Bin 0 -> 2854 bytes resources/old/7gem.png | Bin 0 -> 3274 bytes resources/pause.png | Bin 0 -> 206 bytes resources/title.png | Bin 0 -> 26272 bytes resources/unmute.png | Bin 0 -> 472 bytes src/Game.h | 79 ++ src/Game.m | 596 +++++++++ src/GameController.h | 147 +++ src/GameController.m | 862 ++++++++++++ src/GameView.h | 102 ++ src/GameView.m | 677 ++++++++++ src/Gem.h | 112 ++ src/Gem.m | 278 ++++ src/MyTimerView.h | 62 + src/MyTimerView.m | 165 +++ src/OpenGLSprite.h | 41 + src/OpenGLSprite.m | 261 ++++ src/ScoreBubble.h | 60 + src/ScoreBubble.m | 137 ++ 41 files changed, 10285 insertions(+) create mode 100644 .gitignore create mode 100644 About.xib create mode 100644 English.lproj/InfoPlist.strings create mode 100644 English.lproj/MainMenu.xib create mode 100644 English.lproj/Preferences.xib create mode 100644 English.lproj/kokogems.html create mode 100644 kokogems-Info.plist create mode 100644 kokogems.xcodeproj/project.pbxproj create mode 100644 kokogems_Prefix.pch create mode 100644 main.m create mode 100644 resources/background.png create mode 100644 resources/continue.png create mode 100644 resources/cross.png create mode 100644 resources/gpl2.licence.txt create mode 100644 resources/icon.icns create mode 100644 resources/movehint.png create mode 100644 resources/mute.png create mode 100644 resources/old/1gem.png create mode 100644 resources/old/2gem.png create mode 100644 resources/old/3gem.png create mode 100644 resources/old/4gem.png create mode 100644 resources/old/5gem.png create mode 100644 resources/old/6gem.png create mode 100644 resources/old/7gem.png create mode 100644 resources/pause.png create mode 100644 resources/title.png create mode 100644 resources/unmute.png create mode 100644 src/Game.h create mode 100644 src/Game.m create mode 100644 src/GameController.h create mode 100644 src/GameController.m create mode 100644 src/GameView.h create mode 100644 src/GameView.m create mode 100644 src/Gem.h create mode 100644 src/Gem.m create mode 100644 src/MyTimerView.h create mode 100644 src/MyTimerView.m create mode 100644 src/OpenGLSprite.h create mode 100644 src/OpenGLSprite.m create mode 100644 src/ScoreBubble.h create mode 100644 src/ScoreBubble.m diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1a23a70 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +build/ +*.pbxuser +*.perspectivev3 diff --git a/About.xib b/About.xib new file mode 100644 index 0000000..1ed6133 --- /dev/null +++ b/About.xib @@ -0,0 +1,1166 @@ + + + + 1060 + 10F569 + 788 + 1038.29 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 788 + + + YES + + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + YES + + + YES + + + + YES + + GameController + + + FirstResponder + + + NSApplication + + + 3 + 2 + {{208, 297}, {426, 375}} + -1334312960 + + + + + NSPanel + + + View + + {1.79769e+308, 1.79769e+308} + {399, 199} + + + 256 + + YES + + + 256 + {{17, 214}, {392, 16}} + + YES + + 67239424 + 4194304 + Version 1.3.1 + + LucidaGrande + 13 + 1044 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + + + + 256 + {{20, 20}, {387, 14}} + + YES + + 67239424 + 4194304 + Q29weXJpZ2h0IDIwMDEtMjAwMywgR2lsZXMgV2lsbGlhbXMuICBVbmRlciBHTlUgUHVibGljIExpY2Vu +Y2UgMi4wCi4 + + LucidaGrande + 11 + 3100 + + + + + + + + + 256 + + YES + + + 2304 + + YES + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + CorePasteboardFlavorType 0x6D6F6F76 + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NSTypedFilenamesPboardType:'.SGI' + NSTypedFilenamesPboardType:'8BPS' + NSTypedFilenamesPboardType:'BMPf' + NSTypedFilenamesPboardType:'EPSF' + NSTypedFilenamesPboardType:'FPix' + NSTypedFilenamesPboardType:'GIFf' + NSTypedFilenamesPboardType:'ICO ' + NSTypedFilenamesPboardType:'JPEG' + NSTypedFilenamesPboardType:'PDF ' + NSTypedFilenamesPboardType:'PICT' + NSTypedFilenamesPboardType:'PNGf' + NSTypedFilenamesPboardType:'PNTG' + NSTypedFilenamesPboardType:'TIFF' + NSTypedFilenamesPboardType:'TPIC' + NSTypedFilenamesPboardType:'qtif' + NSTypedFilenamesPboardType:BMP + NSTypedFilenamesPboardType:CUR + NSTypedFilenamesPboardType:FAX + NSTypedFilenamesPboardType:FPIX + NSTypedFilenamesPboardType:FPX + NSTypedFilenamesPboardType:GIF + NSTypedFilenamesPboardType:ICNS + NSTypedFilenamesPboardType:ICO + NSTypedFilenamesPboardType:JPEG + NSTypedFilenamesPboardType:JPG + NSTypedFilenamesPboardType:MAC + NSTypedFilenamesPboardType:PCT + NSTypedFilenamesPboardType:PDF + NSTypedFilenamesPboardType:PICT + NSTypedFilenamesPboardType:PNG + NSTypedFilenamesPboardType:PNT + NSTypedFilenamesPboardType:PNTG + NSTypedFilenamesPboardType:PSD + NSTypedFilenamesPboardType:QTI + NSTypedFilenamesPboardType:QTIF + NSTypedFilenamesPboardType:RGB + NSTypedFilenamesPboardType:SGI + NSTypedFilenamesPboardType:TARGA + NSTypedFilenamesPboardType:TGA + NSTypedFilenamesPboardType:TIF + NSTypedFilenamesPboardType:TIFF + NSTypedFilenamesPboardType:bmp + NSTypedFilenamesPboardType:cur + NSTypedFilenamesPboardType:eps + NSTypedFilenamesPboardType:fax + NSTypedFilenamesPboardType:fpix + NSTypedFilenamesPboardType:fpx + NSTypedFilenamesPboardType:gif + NSTypedFilenamesPboardType:icns + NSTypedFilenamesPboardType:ico + NSTypedFilenamesPboardType:jpeg + NSTypedFilenamesPboardType:jpg + NSTypedFilenamesPboardType:mac + NSTypedFilenamesPboardType:pct + NSTypedFilenamesPboardType:pdf + NSTypedFilenamesPboardType:pict + NSTypedFilenamesPboardType:png + NSTypedFilenamesPboardType:pnt + NSTypedFilenamesPboardType:pntg + NSTypedFilenamesPboardType:psd + NSTypedFilenamesPboardType:qti + NSTypedFilenamesPboardType:qtif + NSTypedFilenamesPboardType:rgb + NSTypedFilenamesPboardType:sgi + NSTypedFilenamesPboardType:targa + NSTypedFilenamesPboardType:tga + NSTypedFilenamesPboardType:tif + NSTypedFilenamesPboardType:tiff + NXTypedFilenamePboardType:eps + NXTypedFilenamePboardType:tif + NXTypedFilenamePboardType:tiff + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {368, 614} + + + + + + SmV3ZWxUb3kKYSBzaW1wbGUgZ2FtZSBwbGF5ZWQgYWdhaW5zdCB0aGUgY2xvY2suCsKpIDIwMDEsMjAw +MiAgR2lsZXMgV2lsbGlhbXMgd2l0aCBNaWtlIFdlc3NsZXIgYW5kIG90aGVycy4KClNvdXJjZSBjb2Rl +IGF2YWlsYWJsZSBhdDoKaHR0cDovL3d3dy5hZWdpZGlhbi5vcmcvamV3ZWx0b3kvCgpFeHRyYSBiYWNr +Z3JvdW5kIGdyYXBoaWNzOgp0aGFua3MgdG8gTWF0dGllIGFuZCBUaGUgT2dyZQoKTG9jYWxpemF0aW9u +IGNyZWRpdHM6Ckdlcm1hbglDYXNleSBEYW5pZWxscwpEdXRjaAlSb24gSGVuZHJpY2t4CkZyZW5jaAlQ +ZXRlciAobGF2YWNoZSBtZXVoaCkKSmFwYW5lc2UJTUlaVQoKQWRkaXRpb25hbCBHcmFwaGljczoKRXJp +YyBDaGVycnkKCkxpY2Vuc2U6CiAgICBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNh +biByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdO +VSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBG +b3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRp +b24pIGFueSBsYXRlciB2ZXJzaW9uLgoKICAgIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0 +aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdp +dGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVT +UyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNl +bnNlIGZvciBtb3JlIGRldGFpbHMuCgogICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBv +ZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIHByb2dyYW07IGlm +IG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwgNTkgVGVtcGxl +IFBsYWNlLCBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEzMDcgIFVTQQoKKFRoZSBHTlUgR2Vu +ZXJhbCBQdWJsaWMgTGljZW5zZSBpcyBsb2NhdGVkIGluIHRoZSBmb2xkZXIgSmV3ZWx0b3kuYXBwL0Nv +bnRlbnRzL1Jlc291cmNlcyk + + + YES + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + Helvetica-Bold + 18 + 16 + + + 2 + 0.05000000074505806 + + YES + + 28 + + + 56 + + + 84 + + + 112 + + + 140 + + + 168 + + + 196 + + + 224 + + + 252 + + + 280 + + + 308 + + + 336 + + + 1 + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + Helvetica + 13 + 16 + + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + Helvetica-Oblique + 13 + 16 + + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + + 4 + 0.05000000074505806 + + YES + + + + + + + + + + + + + + 1 + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + Helvetica-Bold + 13 + 16 + + + 2 + 0.05000000074505806 + + YES + + + + + + + + + + + + + + 1 + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + + 4 + 72 + 72 + 0.05000000074505806 + + YES + + 180 + + + 1 + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + Helvetica-Oblique + 12 + 16 + + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + Helvetica + 12 + 16 + + + + + + YES + + YES + NSFont + NSParagraphStyle + + + YES + + + 4 + 0.05000000074505806 + + YES + + + + + + + + + + + + + + 1 + + + + + + CAApAToCAQMaASEEJwEGBAUBCQQXATgFDQYBBwoFBAcBBSwBsQUDWQg + + + + + YES + + + 6 + + + + 368 + 1 + + + 2924 + 0 + + + 3 + MQA + + + YES + + YES + NSBackgroundColor + NSColor + + + YES + + 6 + System + selectedTextBackgroundColor + + + + 6 + System + selectedTextColor + + + + + + + YES + + YES + NSColor + NSCursor + NSUnderline + + + YES + + 1 + MCAwIDEAA + + + {8, -8} + 13 + + + + + + + 6 + {369, 1e+07} + {369, 162} + + + + {{1, 1}, {369, 162}} + + + + + + {1, -1} + 0 + + 4 + + + + 256 + {{370, 1}, {15, 162}} + + YES + + _doScroller: + 0.26384365558624268 + + + + -2147483392 + {{-100, -100}, {87, 18}} + + 1 + + _doScroller: + 1 + 0.94565218687057495 + + + {{20, 39}, {386, 164}} + + + 82 + + + + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{23, 238}, {383, 117}} + + YES + + 130560 + 33554432 + + NSImage + title + + 0 + 0 + 0 + NO + + YES + + + {426, 375} + + + {{0, 0}, {1600, 1178}} + {399, 221} + {1.79769e+308, 1.79769e+308} + + + + + YES + + + aboutPanel + + + + 24 + + + + delegate + + + + 25 + + + + + YES + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 21 + + + YES + + + + InfoPanel + + + 17 + + + YES + + + + + + + + + 18 + + + YES + + + + + + 19 + + + YES + + + + + + 22 + + + YES + + + + + + + + 15 + + + + + 23 + + + YES + + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 30 + + + + + 31 + + + + + -3 + + + Application + + + + + YES + + YES + 15.IBPluginDependency + 15.ImportedFromIB2 + 17.IBPluginDependency + 17.ImportedFromIB2 + 18.IBPluginDependency + 18.ImportedFromIB2 + 19.IBPluginDependency + 19.ImportedFromIB2 + 21.IBEditorWindowLastContentRect + 21.IBPluginDependency + 21.IBWindowTemplateEditedContentRect + 21.ImportedFromIB2 + 21.windowTemplate.hasMinSize + 21.windowTemplate.minSize + 22.IBPluginDependency + 22.ImportedFromIB2 + 23.IBPluginDependency + 23.ImportedFromIB2 + 30.IBShouldRemoveOnLegacySave + 31.IBShouldRemoveOnLegacySave + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{362, 367}, {426, 375}} + com.apple.InterfaceBuilder.CocoaPlugin + {{362, 367}, {426, 375}} + + + {399, 199} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + YES + + + YES + + + + + YES + + + YES + + + + 31 + + + + YES + + FirstResponder + + IBUserSource + + + + + GameController + NSObject + + YES + + YES + abortGame: + orderFrontAboutPanel: + orderFrontPreferencesPanel: + receiveHiScoreName: + startNewGame: + toggleMute: + togglePauseMode: + + + YES + id + id + id + id + id + id + id + + + + YES + + YES + abortGame: + orderFrontAboutPanel: + orderFrontPreferencesPanel: + receiveHiScoreName: + startNewGame: + toggleMute: + togglePauseMode: + + + YES + + abortGame: + id + + + orderFrontAboutPanel: + id + + + orderFrontPreferencesPanel: + id + + + receiveHiScoreName: + id + + + startNewGame: + id + + + toggleMute: + id + + + togglePauseMode: + id + + + + + YES + + YES + abortGameButton + abortGameMenuItem + aboutPanel + bonusTextField + easyGameButton + easyGameMenuItem + freePlayMenuItem + gameView + gameWindow + hardGameButton + hardGameMenuItem + hiScorePanel + hiScorePanelNameTextField + hiScorePanelScoreTextField + muteButton + muteMenuItem + pauseGameButton + pauseGameMenuItem + prefsAlternateGraphicsButton + prefsPanel + prefsStandardGraphicsButton + scoreTextField + timerView + toughGameButton + toughGameMenuItem + + + YES + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + id + + + + YES + + YES + abortGameButton + abortGameMenuItem + aboutPanel + bonusTextField + easyGameButton + easyGameMenuItem + freePlayMenuItem + gameView + gameWindow + hardGameButton + hardGameMenuItem + hiScorePanel + hiScorePanelNameTextField + hiScorePanelScoreTextField + muteButton + muteMenuItem + pauseGameButton + pauseGameMenuItem + prefsAlternateGraphicsButton + prefsPanel + prefsStandardGraphicsButton + scoreTextField + timerView + toughGameButton + toughGameMenuItem + + + YES + + abortGameButton + id + + + abortGameMenuItem + id + + + aboutPanel + id + + + bonusTextField + id + + + easyGameButton + id + + + easyGameMenuItem + id + + + freePlayMenuItem + id + + + gameView + id + + + gameWindow + id + + + hardGameButton + id + + + hardGameMenuItem + id + + + hiScorePanel + id + + + hiScorePanelNameTextField + id + + + hiScorePanelScoreTextField + id + + + muteButton + id + + + muteMenuItem + id + + + pauseGameButton + id + + + pauseGameMenuItem + id + + + prefsAlternateGraphicsButton + id + + + prefsPanel + id + + + prefsStandardGraphicsButton + id + + + scoreTextField + id + + + timerView + id + + + toughGameButton + id + + + toughGameMenuItem + id + + + + + IBUserSource + + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + + 3 + + title + {128, 128} + + + diff --git a/English.lproj/InfoPlist.strings b/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/English.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/English.lproj/MainMenu.xib b/English.lproj/MainMenu.xib new file mode 100644 index 0000000..6f22663 --- /dev/null +++ b/English.lproj/MainMenu.xib @@ -0,0 +1,2568 @@ + + + + 1060 + 10F569 + 788 + 1038.29 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 788 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + NSApplication + + + + FirstResponder + + + NSApplication + + + 7 + 2 + {{456, 216}, {384, 512}} + 1886912512 + Koko Gems + NSWindow + + View + + {384, 512} + {384, 512} + + + 256 + + + + 256 + {{20, 104}, {344, 16}} + + MyTimerView + NSView + + + + 256 + {{133, 71}, {119, 25}} + + YES + + 67239424 + 138412032 + 000000000 + + LucidaGrande + 18 + 16 + + + YES + + 1 + MCAwIDAAA + + + 1 + MSAxIDAAA + + + + + + 256 + {{258, 18}, {108, 30}} + + YES + + 604110336 + 137887744 + End Game + + LucidaGrande + 13 + 1044 + + + -2038021889 + 2 + + Helvetica + 13 + 16 + + + q + 200 + 25 + + + + + 256 + {{96, 73}, {32, 17}} + + YES + + 67239424 + 71303168 + x1 + + LucidaGrande-Bold + 13 + 2072 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + + + + 256 + {{20, 20}, {75, 25}} + + YES + + 67239424 + 137887744 + Easy + + + -2038021889 + 6 + + + + 200 + 25 + + + + + 256 + {{95, 20}, {75, 25}} + + YES + + 67239424 + 137887744 + Hard + + + -2038021889 + 6 + + + + 200 + 25 + + + + + 256 + {{170, 20}, {75, 25}} + + YES + + 67239424 + 137887744 + Tough + + + -2038021889 + 6 + + + + 200 + 25 + + + + + 256 + {{338, 71}, {26, 25}} + + YES + + 604110336 + 0 + + + LucidaGrande + 10 + 2843 + + + -923533057 + 6 + + NSImage + pause + + + NSImage + continue + + + + + + 200 + 25 + + + + + 256 + {{20, 71}, {26, 25}} + + YES + + 67239424 + 131072 + mute + + + -923533057 + 6 + + NSImage + unmute + + + NSImage + mute + + + + + + 200 + 25 + + + + + 301 + {{0, 128}, {384, 384}} + + + + AAAADAAAAIAAAAAAA + + + + + {384, 512} + + + {{0, 0}, {1600, 1178}} + {384, 534} + {384, 534} + KokoGemsWindow + + + MainMenu + + + + Koko Gems + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + Koko Gems + + + + About Koko Gems + + 2147483647 + + + + + + Preferences... + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + + Services + + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide Koko Gems + h + 1048576 + 2147483647 + + + + + + Hide Others + H + 1048576 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit Koko Gems + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + Game + + 1048576 + 2147483647 + + + submenuAction: + + Game + + + + New Easy Game + 1 + 1048576 + 2147483647 + + + + + + New Hard Game + 2 + 1048576 + 2147483647 + + + + + + New Tough Game + 3 + 1048576 + 2147483647 + + + + + + Free Play (no timer) + 4 + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Show High Scores + s + 1048576 + 2147483647 + + + + + + Reset All High Scores + r + 1572864 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Mute Game + M + 1048576 + 2147483647 + + + + + + Pause Game + p + 1048576 + 2147483647 + + + + + + End Game + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + Window + + + + + Minimize + m + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 1048576 + 2147483647 + + + submenuAction: + + + Help + + + + + JewelToy Help + ? + 1048576 + 2147483647 + + + + + + + + _NSMainMenu + + + GameController + + + 1 + 2 + {{297, 480}, {240, 160}} + 1886912512 + Your High Score + NSPanel + + View + + {1.79769e+308, 1.79769e+308} + {240, 5} + + + 256 + + + + 256 + {{61, 56}, {119, 25}} + + YES + + 67239424 + 138412032 + 000000000 + + + YES + + + + + + + 256 + {{17, 126}, {206, 14}} + + YES + + 67239424 + 138412032 + you got a + + LucidaGrande + 11 + 16 + + + + + + + + + 256 + {{20, 89}, {200, 41}} + + YES + + 67239424 + 138412032 + High Score! + + AmericanTypewriter-Bold + 24 + 16 + + + + + 1 + MSAwIDAAA + + + + + + 256 + {{183, 0}, {42, 28}} + + YES + + 67239424 + 138018816 + OK + + + -2038284033 + 1 + + Helvetica + 11 + 16 + + + DQ + 200 + 25 + + + + + 256 + {{20, 26}, {200, 22}} + + YES + + -1808662975 + 134218752 + Anonymous + + + YES + + + + + + {{1, 1}, {240, 160}} + + {{0, 0}, {1600, 1178}} + {240, 27} + {1.79769e+308, 1.79769e+308} + hiScoreSheet + + + + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + showHelp: + + + + 122 + + + + terminate: + + + + 139 + + + + hideOtherApplications: + + + + 146 + + + + hide: + + + + 152 + + + + unhideAllApplications: + + + + 153 + + + + scoreTextField + + + + 209 + + + + timerView + + + + 210 + + + + startNewGame: + + + + 212 + + + + startNewGame: + + + + 213 + + + + abortGame: + + + + 215 + + + + abortGameButton + + + + 216 + + + + abortGame: + + + + 218 + + + + startNewGame: + + + + 224 + + + + startNewGame: + + + + 225 + + + + easyGameButton + + + + 228 + + + + hardGameButton + + + + 229 + + + + toughGameButton + + + + 230 + + + + bonusTextField + + + + 231 + + + + easyGameMenuItem + + + + 232 + + + + hardGameMenuItem + + + + 233 + + + + toughGameMenuItem + + + + 234 + + + + hiScorePanel + + + + 247 + + + + hiScorePanelScoreTextField + + + + 248 + + + + hiScorePanelNameTextField + + + + 249 + + + + gameWindow + + + + 254 + + + + receiveHiScoreName: + + + + 256 + + + + startNewGame: + + + + 257 + + + + startNewGame: + + + + 258 + + + + abortGameMenuItem + + + + 259 + + + + freePlayMenuItem + + + + 263 + + + + pauseGameMenuItem + + + + 264 + + + + pauseGameButton + + + + 265 + + + + togglePauseMode: + + + + 266 + + + + togglePauseMode: + + + + 267 + + + + startNewGame: + + + + 268 + + + + delegate + + + + 271 + + + + muteButton + + + + 272 + + + + muteMenuItem + + + + 273 + + + + toggleMute: + + + + 274 + + + + toggleMute: + + + + 275 + + + + orderFrontAboutPanel: + + + + 276 + + + + receiveHiScoreName: + + + + 278 + + + + orderFrontPreferencesPanel: + + + + 279 + + + + showHighScores: + + + + 283 + + + + showHighScoresMenuItem + + + + 286 + + + + resetHighScores: + + + + 288 + + + + resetHighScoresMenuItem + + + + 289 + + + + gameView + + + + 291 + + + + gameController + + + + 292 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 21 + + + + + + GameWindow + + + 2 + + + + + + + + + + + + + + + + + 195 + + + + + 196 + + + + + + + + 197 + + + + + + + + 214 + + + + + + + + 219 + + + + + + + + 220 + + + + + + + + 221 + + + + + + + + 260 + + + + + + + + 269 + + + + + + + + 290 + + + + + 29 + + + + + + + + + MainMenu + + + 19 + + + + + + + + 24 + + + + + + + + + + 5 + + + + + 23 + + + + + 92 + + + + + 56 + + + + + + + + 57 + + + + + + + + + + + + + + + + + 58 + + + + + 129 + + + + + 131 + + + + + + + + 130 + + + + + 134 + + + + + 136 + + + + + 143 + + + + + 144 + + + + + 145 + + + + + 149 + + + + + 150 + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + + 82 + + + + + 217 + + + + + 222 + + + + + 223 + + + + + 240 + + + + + 261 + + + + + 262 + + + + + 270 + + + + + 280 + + + + + 281 + + + + + 287 + + + + + 103 + + + + + + + + 106 + + + + + + + + 111 + + + + + 206 + + + GameController + + + 241 + + + + + + HiScoreSheet + + + 242 + + + + + + + + + + + + 244 + + + + + + + + 246 + + + + + + + + 252 + + + + + + + + 253 + + + + + + + + 277 + + + + + + + + 294 + + + + + 295 + + + + + 296 + + + + + 297 + + + + + 298 + + + + + 299 + + + + + 300 + + + + + 301 + + + + + 302 + + + + + 303 + + + + + 304 + + + + + 305 + + + + + 306 + + + + + -3 + + + Application + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{558, 669}, {64, 6}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + {{524, 32}, {384, 512}} + com.apple.InterfaceBuilder.CocoaPlugin + {{524, 32}, {384, 512}} + + + + + {384, 512} + {384, 512} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{502, 672}, {194, 53}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + {240, 5} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{333, 725}, {301, 20}} + com.apple.InterfaceBuilder.CocoaPlugin + + GameView + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{345, 552}, {213, 173}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{445, 522}, {236, 203}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + 306 + + + + + FirstResponder + NSObject + + IBUserSource + + + + + GameController + NSObject + + id + id + id + id + id + id + id + id + id + id + + + + abortGame: + id + + + orderFrontAboutPanel: + id + + + orderFrontPreferencesPanel: + id + + + prefsGraphicDropAction: + id + + + receiveHiScoreName: + id + + + resetHighScores: + id + + + showHighScores: + id + + + startNewGame: + id + + + toggleMute: + id + + + togglePauseMode: + id + + + + NSButton + NSMenuItem + NSPanel + NSTextField + NSButton + NSMenuItem + NSMenuItem + GameView + NSWindow + NSButton + NSMenuItem + NSPanel + NSTextField + NSTextField + NSImageView + NSImageView + NSImageView + NSImageView + NSImageView + NSImageView + NSImageView + NSButton + NSMenuItem + NSButton + NSMenuItem + NSButton + NSImageView + NSPanel + NSButton + NSMenuItem + NSTextField + NSMenuItem + MyTimerView + NSButton + NSMenuItem + + + + abortGameButton + NSButton + + + abortGameMenuItem + NSMenuItem + + + aboutPanel + NSPanel + + + bonusTextField + NSTextField + + + easyGameButton + NSButton + + + easyGameMenuItem + NSMenuItem + + + freePlayMenuItem + NSMenuItem + + + gameView + GameView + + + gameWindow + NSWindow + + + hardGameButton + NSButton + + + hardGameMenuItem + NSMenuItem + + + hiScorePanel + NSPanel + + + hiScorePanelNameTextField + NSTextField + + + hiScorePanelScoreTextField + NSTextField + + + iv1 + NSImageView + + + iv2 + NSImageView + + + iv3 + NSImageView + + + iv4 + NSImageView + + + iv5 + NSImageView + + + iv6 + NSImageView + + + iv7 + NSImageView + + + muteButton + NSButton + + + muteMenuItem + NSMenuItem + + + pauseGameButton + NSButton + + + pauseGameMenuItem + NSMenuItem + + + prefsAlternateGraphicsButton + NSButton + + + prefsAlternateGraphicsImageView + NSImageView + + + prefsPanel + NSPanel + + + prefsStandardGraphicsButton + NSButton + + + resetHighScoresMenuItem + NSMenuItem + + + scoreTextField + NSTextField + + + showHighScoresMenuItem + NSMenuItem + + + timerView + MyTimerView + + + toughGameButton + NSButton + + + toughGameMenuItem + NSMenuItem + + + + IBUserSource + + + + + GameView + NSOpenGLView + + GameController + id + + + + gameController + GameController + + + legend + id + + + + IBUserSource + + + + + MyTimerView + NSView + + target + id + + + target + + target + id + + + + IBUserSource + + + + + + + NSActionCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSActionCell.h + + + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSButton + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSButton.h + + + + NSButtonCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSButtonCell.h + + + + NSCell + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSCell.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSImageView + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSImageView.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSMenuItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSOpenGLView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSOpenGLView.h + + + + NSPanel + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSPanel.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSTextField + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSTextField.h + + + + NSTextFieldCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSTextFieldCell.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + ../kokogems.xcodeproj + 3 + + {9, 8} + {7, 2} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + + + diff --git a/English.lproj/Preferences.xib b/English.lproj/Preferences.xib new file mode 100644 index 0000000..24528e0 --- /dev/null +++ b/English.lproj/Preferences.xib @@ -0,0 +1,1933 @@ + + + + 1060 + 10F569 + 788 + 1038.29 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 788 + + + YES + + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + YES + + + YES + + + + YES + + GameController + + + FirstResponder + + + NSApplication + + + 3 + 2 + {{93, 516}, {375, 214}} + 1886912512 + Preferences + NSPanel + + View + + {375, 214} + {375, 214} + + + 256 + + YES + + + 256 + {{17, 144}, {164, 52}} + + YES + 2 + 1 + + YES + + -2080244224 + 0 + Use standard graphics + + LucidaGrande + 13 + 1044 + + + 1211912703 + 0 + + NSRadioButton + + + + + + 200 + 25 + + + 67239424 + 0 + Use alternate graphics + + + 1 + 1211912703 + 0 + + + + 200 + 25 + + + {164, 25} + {4, 2} + 1143472128 + NSActionCell + + 67239424 + 0 + Radio + + 1211912703 + 0 + + + 400 + 75 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 3 + MQA + + + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{187, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 1gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{211, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 2gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{235, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 3gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{259, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 4gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{283, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 5gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{307, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 6gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{331, 170}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 7gem + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{187, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 1gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{235, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 3gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{259, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 4gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{283, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 5gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{331, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 7gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{307, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 6gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{211, 146}, {24, 24}} + + YES + + 130560 + 33554432 + + NSImage + 2gemA + + 0 + 0 + 0 + NO + + YES + + + + 256 + {{301, 19}, {59, 28}} + + YES + + 67239424 + 138018816 + OK + + LucidaGrande + 11 + 16 + + + -2038284033 + 1 + + Helvetica + 11 + 16 + + + DQ + 200 + 25 + + + + + 256 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{128, 103}, {230, 38}} + + YES + + 270663168 + 0 + 0 + 1 + 2 + NO + + YES + + + + 256 + {{19, 106}, {104, 32}} + + YES + + 67239424 + 71303168 + drag gem graphics to here: + + LucidaGrande + 10 + 2843 + + + + + 6 + System + controlTextColor + + 3 + MAA + + + + + + + 256 + {{17, 79}, {225, 18}} + + YES + + 67239424 + 131072 + Use custom backgrounds from folder: + + + 1211912703 + 2 + + NSSwitch + + + + 200 + 25 + + + + + 256 + {{18, 54}, {336, 19}} + + YES + + -1536033215 + 4195328 + + + + YES + + 6 + System + textBackgroundColor + + + + 6 + System + textColor + + + + + + + 256 + {{266, 74}, {94, 28}} + + YES + + 604110336 + 138018816 + Select Folder + + + -2038284033 + 1 + + + + + + 200 + 25 + + + + {375, 214} + + + {{0, 0}, {1024, 746}} + {375, 236} + {375, 236} + + + + + YES + + + delegate + + + + 36 + + + + performClose: + + + + 37 + + + + prefsStandardGraphicsButton + + + + 38 + + + + prefsAlternateGraphicsButton + + + + 39 + + + + prefsPanel + + + + 40 + + + + prefsAlternateGraphicsImageView + + + + 44 + + + + iv1 + + + + 45 + + + + iv2 + + + + 46 + + + + iv3 + + + + 47 + + + + iv4 + + + + 48 + + + + iv5 + + + + 49 + + + + iv6 + + + + 50 + + + + iv7 + + + + 51 + + + + prefsGraphicDropAction: + + + + 52 + + + + prefsCustomBackgroundCheckbox + + + + 56 + + + + prefsSelectFolderButton + + + + 57 + + + + prefsCustomBackgroundFolderTextField + + + + 58 + + + + prefsCustomBackgroundCheckboxAction: + + + + 59 + + + + prefsSelectFolderButtonAction: + + + + 60 + + + + + YES + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 5 + + + YES + + + + Panel + + + 6 + + + YES + + + + + + + + + + + + + + + + + + + + + + + + + + 7 + + + YES + + + + + + + + 8 + + + + + 9 + + + + + 12 + + + YES + + + + + + 13 + + + YES + + + + + + 14 + + + YES + + + + + + 15 + + + YES + + + + + + 16 + + + YES + + + + + + 17 + + + YES + + + + + + 18 + + + YES + + + + + + 26 + + + YES + + + + + + 27 + + + YES + + + + + + 28 + + + YES + + + + + + 29 + + + YES + + + + + + 30 + + + YES + + + + + + 31 + + + YES + + + + + + 32 + + + YES + + + + + + 34 + + + YES + + + + + + 41 + + + YES + + + + + + 42 + + + YES + + + + + + 53 + + + YES + + + + + + 54 + + + YES + + + + + + 55 + + + YES + + + + + + 62 + + + + + 63 + + + + + 64 + + + + + 65 + + + + + 66 + + + + + 67 + + + + + 68 + + + + + 69 + + + + + 70 + + + + + 71 + + + + + 72 + + + + + 73 + + + + + 74 + + + + + 75 + + + + + 76 + + + + + 77 + + + + + 78 + + + + + 79 + + + + + 80 + + + + + 81 + + + + + 82 + + + + + -3 + + + Application + + + + + YES + + YES + -3.IBPluginDependency + 12.IBPluginDependency + 12.ImportedFromIB2 + 13.IBPluginDependency + 13.ImportedFromIB2 + 14.IBPluginDependency + 14.ImportedFromIB2 + 15.IBPluginDependency + 15.ImportedFromIB2 + 16.IBPluginDependency + 16.ImportedFromIB2 + 17.IBPluginDependency + 17.ImportedFromIB2 + 18.IBPluginDependency + 18.ImportedFromIB2 + 26.IBPluginDependency + 26.ImportedFromIB2 + 27.IBPluginDependency + 27.ImportedFromIB2 + 28.IBPluginDependency + 28.ImportedFromIB2 + 29.IBPluginDependency + 29.ImportedFromIB2 + 30.IBPluginDependency + 30.ImportedFromIB2 + 31.IBPluginDependency + 31.ImportedFromIB2 + 32.IBPluginDependency + 32.ImportedFromIB2 + 34.IBPluginDependency + 34.ImportedFromIB2 + 41.IBAttributePlaceholdersKey + 41.IBPluginDependency + 41.ImportedFromIB2 + 42.IBPluginDependency + 42.ImportedFromIB2 + 5.IBEditorWindowLastContentRect + 5.IBPluginDependency + 5.IBWindowTemplateEditedContentRect + 5.ImportedFromIB2 + 5.windowTemplate.hasMaxSize + 5.windowTemplate.hasMinSize + 5.windowTemplate.maxSize + 5.windowTemplate.minSize + 53.IBPluginDependency + 53.ImportedFromIB2 + 54.IBPluginDependency + 54.ImportedFromIB2 + 55.IBPluginDependency + 55.ImportedFromIB2 + 6.IBPluginDependency + 6.ImportedFromIB2 + 62.IBPluginDependency + 63.IBPluginDependency + 64.IBPluginDependency + 65.IBPluginDependency + 66.IBPluginDependency + 67.IBPluginDependency + 68.IBPluginDependency + 69.IBPluginDependency + 7.IBPluginDependency + 7.ImportedFromIB2 + 70.IBPluginDependency + 71.IBPluginDependency + 72.IBPluginDependency + 73.IBPluginDependency + 74.IBPluginDependency + 75.IBPluginDependency + 76.IBPluginDependency + 77.IBPluginDependency + 78.IBPluginDependency + 79.IBPluginDependency + 8.IBPluginDependency + 8.ImportedFromIB2 + 80.IBPluginDependency + 81.IBPluginDependency + 82.IBPluginDependency + 9.IBPluginDependency + 9.ImportedFromIB2 + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + ToolTip + + ToolTip + + drag a 7:1 ratio graphic of your gems into this well + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + {{316, 542}, {375, 214}} + com.apple.InterfaceBuilder.CocoaPlugin + {{316, 542}, {375, 214}} + + + + {375, 214} + {375, 214} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + YES + + + YES + + + + + YES + + + YES + + + + 82 + + + + YES + + FirstResponder + NSObject + + IBUserSource + + + + + GameController + NSObject + + YES + + YES + abortGame: + orderFrontAboutPanel: + orderFrontPreferencesPanel: + prefsCustomBackgroundCheckboxAction: + prefsGraphicDropAction: + prefsSelectFolderButtonAction: + receiveHiScoreName: + resetHighScores: + showHighScores: + startNewGame: + toggleMute: + togglePauseMode: + + + YES + id + id + id + id + id + id + id + id + id + id + id + id + + + + YES + + YES + abortGame: + orderFrontAboutPanel: + orderFrontPreferencesPanel: + prefsCustomBackgroundCheckboxAction: + prefsGraphicDropAction: + prefsSelectFolderButtonAction: + receiveHiScoreName: + resetHighScores: + showHighScores: + startNewGame: + toggleMute: + togglePauseMode: + + + YES + + abortGame: + id + + + orderFrontAboutPanel: + id + + + orderFrontPreferencesPanel: + id + + + prefsCustomBackgroundCheckboxAction: + id + + + prefsGraphicDropAction: + id + + + prefsSelectFolderButtonAction: + id + + + receiveHiScoreName: + id + + + resetHighScores: + id + + + showHighScores: + id + + + startNewGame: + id + + + toggleMute: + id + + + togglePauseMode: + id + + + + + YES + + YES + abortGameButton + abortGameMenuItem + aboutPanel + bonusTextField + easyGameButton + easyGameMenuItem + freePlayMenuItem + gameView + gameWindow + hardGameButton + hardGameMenuItem + hiScorePanel + hiScorePanelNameTextField + hiScorePanelScoreTextField + iv1 + iv2 + iv3 + iv4 + iv5 + iv6 + iv7 + muteButton + muteMenuItem + pauseGameButton + pauseGameMenuItem + prefsAlternateGraphicsButton + prefsAlternateGraphicsImageView + prefsCustomBackgroundCheckbox + prefsCustomBackgroundFolderTextField + prefsPanel + prefsSelectFolderButton + prefsStandardGraphicsButton + resetHighScoresMenuItem + scoreTextField + showHighScoresMenuItem + timerView + toughGameButton + toughGameMenuItem + + + YES + NSButton + NSMenuItem + NSPanel + NSTextField + NSButton + NSMenuItem + NSMenuItem + GameView + NSWindow + NSButton + NSMenuItem + NSPanel + NSTextField + NSTextField + NSImageView + NSImageView + NSImageView + NSImageView + NSImageView + NSImageView + NSImageView + NSButton + NSMenuItem + NSButton + NSMenuItem + NSButton + NSImageView + NSButton + NSTextField + NSPanel + NSButton + NSButton + NSMenuItem + NSTextField + NSMenuItem + MyTimerView + NSButton + NSMenuItem + + + + YES + + YES + abortGameButton + abortGameMenuItem + aboutPanel + bonusTextField + easyGameButton + easyGameMenuItem + freePlayMenuItem + gameView + gameWindow + hardGameButton + hardGameMenuItem + hiScorePanel + hiScorePanelNameTextField + hiScorePanelScoreTextField + iv1 + iv2 + iv3 + iv4 + iv5 + iv6 + iv7 + muteButton + muteMenuItem + pauseGameButton + pauseGameMenuItem + prefsAlternateGraphicsButton + prefsAlternateGraphicsImageView + prefsCustomBackgroundCheckbox + prefsCustomBackgroundFolderTextField + prefsPanel + prefsSelectFolderButton + prefsStandardGraphicsButton + resetHighScoresMenuItem + scoreTextField + showHighScoresMenuItem + timerView + toughGameButton + toughGameMenuItem + + + YES + + abortGameButton + NSButton + + + abortGameMenuItem + NSMenuItem + + + aboutPanel + NSPanel + + + bonusTextField + NSTextField + + + easyGameButton + NSButton + + + easyGameMenuItem + NSMenuItem + + + freePlayMenuItem + NSMenuItem + + + gameView + GameView + + + gameWindow + NSWindow + + + hardGameButton + NSButton + + + hardGameMenuItem + NSMenuItem + + + hiScorePanel + NSPanel + + + hiScorePanelNameTextField + NSTextField + + + hiScorePanelScoreTextField + NSTextField + + + iv1 + NSImageView + + + iv2 + NSImageView + + + iv3 + NSImageView + + + iv4 + NSImageView + + + iv5 + NSImageView + + + iv6 + NSImageView + + + iv7 + NSImageView + + + muteButton + NSButton + + + muteMenuItem + NSMenuItem + + + pauseGameButton + NSButton + + + pauseGameMenuItem + NSMenuItem + + + prefsAlternateGraphicsButton + NSButton + + + prefsAlternateGraphicsImageView + NSImageView + + + prefsCustomBackgroundCheckbox + NSButton + + + prefsCustomBackgroundFolderTextField + NSTextField + + + prefsPanel + NSPanel + + + prefsSelectFolderButton + NSButton + + + prefsStandardGraphicsButton + NSButton + + + resetHighScoresMenuItem + NSMenuItem + + + scoreTextField + NSTextField + + + showHighScoresMenuItem + NSMenuItem + + + timerView + MyTimerView + + + toughGameButton + NSButton + + + toughGameMenuItem + NSMenuItem + + + + + IBUserSource + + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + + 3 + + YES + + YES + 1gem + 1gemA + 2gem + 2gemA + 3gem + 3gemA + 4gem + 4gemA + 5gem + 5gemA + 6gem + 6gemA + 7gem + 7gemA + + + YES + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + {128, 128} + + + + diff --git a/English.lproj/kokogems.html b/English.lproj/kokogems.html new file mode 100644 index 0000000..858a3d9 --- /dev/null +++ b/English.lproj/kokogems.html @@ -0,0 +1,242 @@ + + + +JewelToy Help + + + +

+
+JewelToy is a simple game played against the clock. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

+The object of the game is to form vertical or horizontal lines of three or more identical gems. +

+
+ +
+ + +

+You do this by clicking on two adjacent gems, which will swap positions. +
(Alternatively you may click one gem and slide it towards the adjacent gem) +

+
+ +
+ + +

+Two adjacent gems may be swapped only if one or both of them then form a line of three or more identical gems. +

+
+ +
+ + +

+The line then disappears and the gems above fall down to take their place. +

+
+ +
+ + +

+Each line you make scores points and adds time to the clock. Longer lines score higher. +

+
+ +
+ + +

+Each time you manage to beat the clock by pushing it to the maximum you earn a bonus multiplier (which increases the amount you get for each line) and the game speeds up. +

+
+ +
+ + +

+If there is no way to make a line, the current set of gems will be replaced with a brand new set of gems. +

+
+ +
+ + +

+If you don't make a move for twenty seconds the game will try to give you a hint by highlighting a gem you can move. +

+
+ +
+ + +

+You can also play in Free Play mode where there is no timer, no bonus multipliers, and the game ends when you can make no more moves. +

+
+ +
+ + +

+And, should you need to take a break, there is even a pause button. +

+
+ +
+

+ + + + + + + + +
+

+By swapping adjacent pairs of gems ... +

+
+

+attempt to get three gems in a row +

+
+

+ + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+

+

+ + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+

+

+e-mail: Giles Williams <aegidian@mac.com>
+ +

+ + diff --git a/kokogems-Info.plist b/kokogems-Info.plist new file mode 100644 index 0000000..6646c7a --- /dev/null +++ b/kokogems-Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + icon.icns + CFBundleIdentifier + net.exterlulz.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/kokogems.xcodeproj/project.pbxproj b/kokogems.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ad7dec5 --- /dev/null +++ b/kokogems.xcodeproj/project.pbxproj @@ -0,0 +1,407 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + CD6C947C121EC6920033B9EF /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = CD6C947B121EC6920033B9EF /* icon.icns */; }; + CD6C947E121EC6E10033B9EF /* gpl2.licence.txt in Resources */ = {isa = PBXBuildFile; fileRef = CD6C947D121EC6E10033B9EF /* gpl2.licence.txt */; }; + CD6C9481121EC8B50033B9EF /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD6C947F121EC8B50033B9EF /* Preferences.xib */; }; + CD6C9491121EC9400033B9EF /* kokogems.html in Resources */ = {isa = PBXBuildFile; fileRef = CD6C948F121EC9400033B9EF /* kokogems.html */; }; + CD6C94A0121EC97A0033B9EF /* Game.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C9493121EC97A0033B9EF /* Game.m */; }; + CD6C94A1121EC97A0033B9EF /* GameController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C9495121EC97A0033B9EF /* GameController.m */; }; + CD6C94A2121EC97A0033B9EF /* GameView.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C9497121EC97A0033B9EF /* GameView.m */; }; + CD6C94A3121EC97A0033B9EF /* Gem.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C9499121EC97A0033B9EF /* Gem.m */; }; + CD6C94A4121EC97A0033B9EF /* MyTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C949B121EC97A0033B9EF /* MyTimerView.m */; }; + CD6C94A5121EC97A0033B9EF /* OpenGLSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C949D121EC97A0033B9EF /* OpenGLSprite.m */; }; + CD6C94A6121EC97A0033B9EF /* ScoreBubble.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6C949F121EC97A0033B9EF /* ScoreBubble.m */; }; + CD6C94AF121EC9BE0033B9EF /* 1gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94A8121EC9BE0033B9EF /* 1gem.png */; }; + CD6C94B0121EC9BE0033B9EF /* 2gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94A9121EC9BE0033B9EF /* 2gem.png */; }; + CD6C94B1121EC9BE0033B9EF /* 3gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94AA121EC9BE0033B9EF /* 3gem.png */; }; + CD6C94B2121EC9BE0033B9EF /* 4gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94AB121EC9BE0033B9EF /* 4gem.png */; }; + CD6C94B3121EC9BE0033B9EF /* 5gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94AC121EC9BE0033B9EF /* 5gem.png */; }; + CD6C94B4121EC9BE0033B9EF /* 6gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94AD121EC9BE0033B9EF /* 6gem.png */; }; + CD6C94B5121EC9BE0033B9EF /* 7gem.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94AE121EC9BE0033B9EF /* 7gem.png */; }; + CD6C94B7121ECA3B0033B9EF /* About.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94B6121ECA3B0033B9EF /* About.xib */; }; + CD6C94BF121ECA5D0033B9EF /* continue.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94B8121ECA5D0033B9EF /* continue.png */; }; + CD6C94C0121ECA5D0033B9EF /* cross.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94B9121ECA5D0033B9EF /* cross.png */; }; + CD6C94C1121ECA5D0033B9EF /* movehint.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94BA121ECA5D0033B9EF /* movehint.png */; }; + CD6C94C2121ECA5D0033B9EF /* mute.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94BB121ECA5D0033B9EF /* mute.png */; }; + CD6C94C3121ECA5D0033B9EF /* pause.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94BC121ECA5D0033B9EF /* pause.png */; }; + CD6C94C4121ECA5D0033B9EF /* title.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94BD121ECA5D0033B9EF /* title.png */; }; + CD6C94C5121ECA5D0033B9EF /* unmute.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6C94BE121ECA5D0033B9EF /* unmute.png */; }; + CD6C94C9121ECA8F0033B9EF /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6C94C8121ECA8F0033B9EF /* OpenGL.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; + 256AC3F00F4B6AF500CF3369 /* kokogems_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kokogems_Prefix.pch; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* kokogems-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "kokogems-Info.plist"; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* kokogems.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = kokogems.app; sourceTree = BUILT_PRODUCTS_DIR; }; + CD6C947B121EC6920033B9EF /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = icon.icns; path = resources/icon.icns; sourceTree = ""; }; + CD6C947D121EC6E10033B9EF /* gpl2.licence.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = gpl2.licence.txt; path = resources/gpl2.licence.txt; sourceTree = ""; }; + CD6C9480121EC8B50033B9EF /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/Preferences.xib; sourceTree = ""; }; + CD6C9490121EC9400033B9EF /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = English; path = English.lproj/kokogems.html; sourceTree = ""; }; + CD6C9492121EC97A0033B9EF /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Game.h; path = src/Game.h; sourceTree = ""; }; + CD6C9493121EC97A0033B9EF /* Game.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Game.m; path = src/Game.m; sourceTree = ""; }; + CD6C9494121EC97A0033B9EF /* GameController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GameController.h; path = src/GameController.h; sourceTree = ""; }; + CD6C9495121EC97A0033B9EF /* GameController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GameController.m; path = src/GameController.m; sourceTree = ""; }; + CD6C9496121EC97A0033B9EF /* GameView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GameView.h; path = src/GameView.h; sourceTree = ""; }; + CD6C9497121EC97A0033B9EF /* GameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GameView.m; path = src/GameView.m; sourceTree = ""; }; + CD6C9498121EC97A0033B9EF /* Gem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Gem.h; path = src/Gem.h; sourceTree = ""; }; + CD6C9499121EC97A0033B9EF /* Gem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Gem.m; path = src/Gem.m; sourceTree = ""; }; + CD6C949A121EC97A0033B9EF /* MyTimerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MyTimerView.h; path = src/MyTimerView.h; sourceTree = ""; }; + CD6C949B121EC97A0033B9EF /* MyTimerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MyTimerView.m; path = src/MyTimerView.m; sourceTree = ""; }; + CD6C949C121EC97A0033B9EF /* OpenGLSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenGLSprite.h; path = src/OpenGLSprite.h; sourceTree = ""; }; + CD6C949D121EC97A0033B9EF /* OpenGLSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OpenGLSprite.m; path = src/OpenGLSprite.m; sourceTree = ""; }; + CD6C949E121EC97A0033B9EF /* ScoreBubble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScoreBubble.h; path = src/ScoreBubble.h; sourceTree = ""; }; + CD6C949F121EC97A0033B9EF /* ScoreBubble.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ScoreBubble.m; path = src/ScoreBubble.m; sourceTree = ""; }; + CD6C94A8121EC9BE0033B9EF /* 1gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 1gem.png; sourceTree = ""; }; + CD6C94A9121EC9BE0033B9EF /* 2gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 2gem.png; sourceTree = ""; }; + CD6C94AA121EC9BE0033B9EF /* 3gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 3gem.png; sourceTree = ""; }; + CD6C94AB121EC9BE0033B9EF /* 4gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 4gem.png; sourceTree = ""; }; + CD6C94AC121EC9BE0033B9EF /* 5gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 5gem.png; sourceTree = ""; }; + CD6C94AD121EC9BE0033B9EF /* 6gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 6gem.png; sourceTree = ""; }; + CD6C94AE121EC9BE0033B9EF /* 7gem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 7gem.png; sourceTree = ""; }; + CD6C94B6121ECA3B0033B9EF /* About.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = About.xib; sourceTree = ""; }; + CD6C94B8121ECA5D0033B9EF /* continue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = continue.png; path = resources/continue.png; sourceTree = ""; }; + CD6C94B9121ECA5D0033B9EF /* cross.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = cross.png; path = resources/cross.png; sourceTree = ""; }; + CD6C94BA121ECA5D0033B9EF /* movehint.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = movehint.png; path = resources/movehint.png; sourceTree = ""; }; + CD6C94BB121ECA5D0033B9EF /* mute.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = mute.png; path = resources/mute.png; sourceTree = ""; }; + CD6C94BC121ECA5D0033B9EF /* pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pause.png; path = resources/pause.png; sourceTree = ""; }; + CD6C94BD121ECA5D0033B9EF /* title.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = title.png; path = resources/title.png; sourceTree = ""; }; + CD6C94BE121ECA5D0033B9EF /* unmute.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = unmute.png; path = resources/unmute.png; sourceTree = ""; }; + CD6C94C8121ECA8F0033B9EF /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + CD6C94C9121ECA8F0033B9EF /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + CD6C9492121EC97A0033B9EF /* Game.h */, + CD6C9493121EC97A0033B9EF /* Game.m */, + CD6C9494121EC97A0033B9EF /* GameController.h */, + CD6C9495121EC97A0033B9EF /* GameController.m */, + CD6C9496121EC97A0033B9EF /* GameView.h */, + CD6C9497121EC97A0033B9EF /* GameView.m */, + CD6C9498121EC97A0033B9EF /* Gem.h */, + CD6C9499121EC97A0033B9EF /* Gem.m */, + CD6C949A121EC97A0033B9EF /* MyTimerView.h */, + CD6C949B121EC97A0033B9EF /* MyTimerView.m */, + CD6C949C121EC97A0033B9EF /* OpenGLSprite.h */, + CD6C949D121EC97A0033B9EF /* OpenGLSprite.m */, + CD6C949E121EC97A0033B9EF /* ScoreBubble.h */, + CD6C949F121EC97A0033B9EF /* ScoreBubble.m */, + ); + name = Classes; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* kokogems.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* kokogems */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + CD6C94B6121ECA3B0033B9EF /* About.xib */, + CD6C94C8121ECA8F0033B9EF /* OpenGL.framework */, + ); + name = kokogems; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 256AC3F00F4B6AF500CF3369 /* kokogems_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + CD6C94B8121ECA5D0033B9EF /* continue.png */, + CD6C94B9121ECA5D0033B9EF /* cross.png */, + CD6C94BA121ECA5D0033B9EF /* movehint.png */, + CD6C94BB121ECA5D0033B9EF /* mute.png */, + CD6C94BC121ECA5D0033B9EF /* pause.png */, + CD6C94BD121ECA5D0033B9EF /* title.png */, + CD6C94BE121ECA5D0033B9EF /* unmute.png */, + CD6C94A7121EC9BE0033B9EF /* old */, + CD6C948F121EC9400033B9EF /* kokogems.html */, + 8D1107310486CEB800E47090 /* kokogems-Info.plist */, + CD6C947B121EC6920033B9EF /* icon.icns */, + CD6C947D121EC6E10033B9EF /* gpl2.licence.txt */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, + CD6C947F121EC8B50033B9EF /* Preferences.xib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + CD6C94A7121EC9BE0033B9EF /* old */ = { + isa = PBXGroup; + children = ( + CD6C94A8121EC9BE0033B9EF /* 1gem.png */, + CD6C94A9121EC9BE0033B9EF /* 2gem.png */, + CD6C94AA121EC9BE0033B9EF /* 3gem.png */, + CD6C94AB121EC9BE0033B9EF /* 4gem.png */, + CD6C94AC121EC9BE0033B9EF /* 5gem.png */, + CD6C94AD121EC9BE0033B9EF /* 6gem.png */, + CD6C94AE121EC9BE0033B9EF /* 7gem.png */, + ); + name = old; + path = resources/old; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* kokogems */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "kokogems" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = kokogems; + productInstallPath = "$(HOME)/Applications"; + productName = kokogems; + productReference = 8D1107320486CEB800E47090 /* kokogems.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "kokogems" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 29B97314FDCFA39411CA2CEA /* kokogems */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* kokogems */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, + CD6C947C121EC6920033B9EF /* icon.icns in Resources */, + CD6C947E121EC6E10033B9EF /* gpl2.licence.txt in Resources */, + CD6C9481121EC8B50033B9EF /* Preferences.xib in Resources */, + CD6C9491121EC9400033B9EF /* kokogems.html in Resources */, + CD6C94AF121EC9BE0033B9EF /* 1gem.png in Resources */, + CD6C94B0121EC9BE0033B9EF /* 2gem.png in Resources */, + CD6C94B1121EC9BE0033B9EF /* 3gem.png in Resources */, + CD6C94B2121EC9BE0033B9EF /* 4gem.png in Resources */, + CD6C94B3121EC9BE0033B9EF /* 5gem.png in Resources */, + CD6C94B4121EC9BE0033B9EF /* 6gem.png in Resources */, + CD6C94B5121EC9BE0033B9EF /* 7gem.png in Resources */, + CD6C94B7121ECA3B0033B9EF /* About.xib in Resources */, + CD6C94BF121ECA5D0033B9EF /* continue.png in Resources */, + CD6C94C0121ECA5D0033B9EF /* cross.png in Resources */, + CD6C94C1121ECA5D0033B9EF /* movehint.png in Resources */, + CD6C94C2121ECA5D0033B9EF /* mute.png in Resources */, + CD6C94C3121ECA5D0033B9EF /* pause.png in Resources */, + CD6C94C4121ECA5D0033B9EF /* title.png in Resources */, + CD6C94C5121ECA5D0033B9EF /* unmute.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072D0486CEB800E47090 /* main.m in Sources */, + CD6C94A0121EC97A0033B9EF /* Game.m in Sources */, + CD6C94A1121EC97A0033B9EF /* GameController.m in Sources */, + CD6C94A2121EC97A0033B9EF /* GameView.m in Sources */, + CD6C94A3121EC97A0033B9EF /* Gem.m in Sources */, + CD6C94A4121EC97A0033B9EF /* MyTimerView.m in Sources */, + CD6C94A5121EC97A0033B9EF /* OpenGLSprite.m in Sources */, + CD6C94A6121EC97A0033B9EF /* ScoreBubble.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 1DDD58150DA1D0A300B32029 /* English */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; + CD6C947F121EC8B50033B9EF /* Preferences.xib */ = { + isa = PBXVariantGroup; + children = ( + CD6C9480121EC8B50033B9EF /* English */, + ); + name = Preferences.xib; + sourceTree = ""; + }; + CD6C948F121EC9400033B9EF /* kokogems.html */ = { + isa = PBXVariantGroup; + children = ( + CD6C9490121EC9400033B9EF /* English */, + ); + name = kokogems.html; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = kokogems_Prefix.pch; + INFOPLIST_FILE = "kokogems-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = kokogems; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = kokogems_Prefix.pch; + INFOPLIST_FILE = "kokogems-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = kokogems; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "kokogems" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "kokogems" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/kokogems_Prefix.pch b/kokogems_Prefix.pch new file mode 100644 index 0000000..8a5d22b --- /dev/null +++ b/kokogems_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'kokogems' target in the 'kokogems' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/main.m b/main.m new file mode 100644 index 0000000..6a76e01 --- /dev/null +++ b/main.m @@ -0,0 +1,5 @@ +#import + +int main(int argc, char *argv[]) { + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/resources/background.png b/resources/background.png new file mode 100644 index 0000000000000000000000000000000000000000..95e5e706f4a50876f7c56da6c28542d443a37e5d GIT binary patch literal 3351 zcwXxa@N?(olHy`uVBq!ia0y~yU~B+k4mP03lH*(V11Zh|kH}&M25w;xW@MN(M}mQY z=cK2LV@L(#+p7n885DS!Hy-+D&CI{eLfOz^j#s2{@xAXH0tyZaY8#R(kE%K}Ff{5X zFw9|MWMWyw#HJ9n=LQRhfB{2Z0|O&dAS1JYZd?u%3x@=QIY{M-2F4CCeKVk1o(5?J zhX#j`0}L+R;?k@_)0nK*~NZ(rQ kaPJh;E@=ja|Nog8-li?^+3%9J3urxqr>mdKI;Vst03)12^Z)<= literal 0 HcwPel00001 diff --git a/resources/cross.png b/resources/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..8166dbfa6c101fbae44cde9a11478b963b971e43 GIT binary patch literal 1317 zcwPY|1={+FP)|Ip=@QobTJ@{{bc@CaWR?_eKEAf0&ZjfSoQQBIN;9y}*?|V2>RT zjEK1!PGI{-z;rjz?YNbkB2e22OiclEBf!Nnj;n&jvd%!Q%W@CUdxdgN(&_*{7w4s{ z5$bmJ3&3yJDaahHXuAJ1l9^>tE~&xAsuI*Y}^ za-d&04vft$$(LEvlZ;*XhUfb?Ivfr3y_@Hz3XudHkJ)TB9|*$RKXBa8HO8hEgI%=S zf2~y2eS#=Dj8?Az4}ZNx_*KS6zUTQ*PswuEflw&DS<})*@pxL2q_WjwF~)HTpQ1FD zhr_Lphe921c|0F~DT)_7842+y*?A;!Rj#& zmP#Gg5{ZM+Xmn2?5ZGq7+gIHZR0FpzPm;nOpRb}&Rd5I%j%iv`BocXu#&)ZsC}q_Bs2~Wk)oRWDB&1^#RE)*x zbmqxkZzNbyu!Vv?>T%JFQ9D!x;lW%1HjxcF!A7mTWqMMqEk=J`H6CT28^}?C-0}Xe1L0BPO=Rs3;_pg zf&Ly~Sa-_Cmbhi#GWKDi-Cn^9LP~cJj4Z$psNVsTi@C;Wod>4g0nRl5$CJP#Jg~A+ zeLGNgmb!fXpZ=u2W=}XAt-9&t_xrbtqF7*L0Xp5lsb%uc>30-^K<^z3?&rkv3%7gNl)ZUQZ2`E!4-qh7+IeM zPG4IRNPis^gir2HB+{{Xyh%}%k~P_TSwb6_(H^*b!~Fnb!<~w9bbT_Jj%nH<%KgBq zwkACZ?kMmIjnZ_+VxM^3>upb@Qf=XIxL&vWj26ELO~Cupna)oFzr5-3bQhEOL^Aob zs;c#}ET^(+o_@RbGO+7+U}n^69oQWXr?q6VB@hTy^E_|MRRKl7j!Pu|PvFvfvfO^> zg82Q^xE;DzN+Xp038-HJyb7E+<8;1JrjJi7_GEs3{s!If%@y?Yr9NP&PZXOSRIV(y0U3B6Zb0b7u;8`x`=WpotIyEe3`|W?{F8}}l b|NjF3A(m<6DE$2R00000NkvXXu0mjf>cVrD literal 0 HcwPel00001 diff --git a/resources/gpl2.licence.txt b/resources/gpl2.licence.txt new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/resources/gpl2.licence.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/resources/icon.icns b/resources/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..4feb2a90091d30c92a9ca2860aa408a4fced9d06 GIT binary patch literal 40920 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 literal 0 HcwPel00001 diff --git a/resources/movehint.png b/resources/movehint.png new file mode 100644 index 0000000000000000000000000000000000000000..030068cb3426b20a4ef6dbe05accbcaf088c107c GIT binary patch literal 1522 zcwPbW1r7R%P)*!;;b-H!6H*0VD-um8l{X5r=zB&3vtdH^VgFhV)@sTI~@U~oA+mp5@<^ART z{Bvuztl8py?0wun(?8QU+vt6MANv>&KYlF4M;_#hJ3JEGLbj057`<6LVlo z4LsliUsUJyuJx|YSDmj&>zmY6;D=6ecy6;rtS!^Mea~;9TIiVfTjJov%Az)3p~D z0Wq4G0I~%qcsYkuWva4pZ{c3djsr6Tq7xCCz0cm4PyuXwk}KLo2u|>Vn=zIeOWoJp z*SwFskD4FOwU&o1fARbHY;D=vl1KrFPjZRzfS2VSV$yVJx{UAH_MNn*%ur?|QUKyh zWnrna6Unk-l1!miXyj&Cma%tzzp2LLW`D0!+i0AxX!mC zViw*v>>FkpervcDnhH(%-ud2bI+^*RijR z$$BMNF7Sbqyq`n_kXeosQE#qKIuU?pxxhz1YH%eK_!9U+p8hxyAG$wS8Y~S-BZB1s z54gx9KH*&;fQUHu@z}@Bp3R;VMT$aJb~Zmaz{7t(;RMhnL_htJd%|cnTICdg{B+Ip zpH2m@05@bRJXL$6_J-D=HOMId`N07mKBHg>aofqz@GA*E~+4 z62hF|9&!&Q3p_FKfD3%{N{AM~!L#oM8ofp@H?WX_3w+?5cMm`SE>F$Xnycy@b&lMi zVg^2Nl5%1^w>`fHJ_kNmU#Y&5?C`|E3Et2|Xo9KxrS8`~m-bxxR^W+oA}&{7W(?a6 z+wpoPH_%c{ovmJZrChOPn_-(_Td}v;yQ6i-k0nRA)`}0?ZzcPrkG8gCZAl_|5TE4Y z=coEdz*~H{_%M@c%rv?NU4wzKz!)Zo;N;gv?~^{7EociSQUKzUT>Sj>K6tAJs|Goz z^sMwO*G1RG;COI6JQGgp|3<+FPVj;|;;70}WkFG3JTM+DfZPJmzz0t7E^t<5sxqrC zR9zqak6K#DU0?+b+Gim^pPNl0nUwIyn7Yp7IVi2HEDbjcL?Cj|t z?jFV#{iO=PK6t+DOW;hjSL*%kpxc+ z|5`iFI?fUiQUw6A^hD_i|A>EthCm<37ZX7XAn@P-k7W3W2yL3yaoTYjKUoAutb}Ia zfA)X!f8yUmoCx+f&Wnj4CB(tAd66F+F~dhhXwozlrz%eMj`eaPq6xtN`eptyKY@?7 z(2esL7j2yZ@i7khkQe!v3{Q(FA1EKdHzKse#KNd|_3jGzNByH>Yitn_>^O{vA3ql2 zBMk?A0RR63 Y0CWl^2Vf2rXaE2J07*qoM6N<$f{F;6&8pJf-3Y}Fol}rKL7GHvh~IfT=V|7AF{c?YSe-Dk zv~+k+aX~sLN#&eWaB3*2Ry6b>*NFVJW9i~WdO4LYG0}#;*_xlCzyeAhP;`P4l$B9< zM85gQij0Jr%rV$9Gs&{&NXDC)%`V{1-an?nCdkk(&vy1~JB!jaMcp2G6h-H@O|wR@ zhB7l(7l>iD$vf#0B{_;YY7KO%;-gha@_5UY_xN{RNNyohr7!rr9s|IsS|009600{|GBQ-B*CSc3on002ovPDHLkV1hJL B;}!q_ literal 0 HcwPel00001 diff --git a/resources/old/1gem.png b/resources/old/1gem.png new file mode 100644 index 0000000000000000000000000000000000000000..219c775d813c01e518ad97aac463e9054c6c9f1b GIT binary patch literal 2312 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 literal 0 HcwPel00001 diff --git a/resources/old/3gem.png b/resources/old/3gem.png new file mode 100644 index 0000000000000000000000000000000000000000..959f9ae42bbb4be7d6a9fed9d10407f15e0ded5d GIT binary patch literal 2369 zcwPZP3BLA;P)f;ViEbKAhbYRS_?&yV!=e{^kYif>GVDC zp68vp<8+Wxwx1-PBcJ6b|`<&-I=Mw!KKgX00&twA_O+4ms(97~OZL)#fc6dCr zFwJ|pFT|-4m%9!fdS%@65_hLBt1CjL=pp!JTgU+NC2+_0pj=HCzg{? zot+*P47!+^)QJTnuR!?klK>HYiN@|oM50zN}eOgNnq zz;hI!`ub~9Xx_m=0{2CM9H!DZ4Sas_B1tnl_=g|7D*8J+iHYlpDEJs{?CJtgWhE&z zFB0hJNK&B?Ne@Jl!{3I(b~7V6XY79`tS1sUZ$I2nsG|ebCGPF@=jg3yz z_)#jVaiP;sNhKbNh6U$A8&tla;Ge?rW&q`@SC8|xYsVFU_xGQXo@kb)ZI+&BXBe6F4o}M3he)K2_9U@lY)F~1`9=&77Qhn@LnF0RI zH~Vxjcv^?UO+t&a0_dE^Px~HMDAXi$dWjDm`kk(?Pm#&(;=)3UD=J8A2T89)=ydYr zC?qy1DdH++vKns#dw>axAtfeFLum#F9dbWcZ{EC0U%7JBBmnSja_+A23O*J^b(tKN);BakjZ?vOlDGpgO=*+a|!jl(kot}r;Fcx z*J7cmxLF!_@WGKK;gIVw*`yk=jO^YWvBao0j2XNQ9)JmpA=Tecs-$GGQJdc0dc%1e zfje%paGwcuoT@rZ1F9N zUVh>U8a#NAG?o$gd01k&%3#n9A7e`=PQ>VZcXyqJ+Mr==nhZyw$o+Zgrw{bboj#3% zz(&z6?txS_$zZ@%f$Sy}EtN=nL8g3}r9h}o^XD?+bkpJ&N*<*L*x#X z!i6DKTf5yzWnz_wqYxCUv~&$$xR7k7c3+=!h&-b>(!?zE6{?Y5zTDk@|NZxETd-ik zOFp0P50+)QhsnY6VTY}#NFF$Fz+?OiEC4JqTxI-&&Y#aRLkc=S@&wMQ*49HpzvVIq zrZIXc6mlA>wziT`i`0AXk<1L@=4RqoUv;%-XU{3g%F6z?B(QGIoH>7WyWRKPsvpv@ z!(t5ted_DI`lF8^cf|4l4P%B=35REBOjryl=={hibdE8pYigFry;Hu+3*G0^QX?At z<(DKAoV4_qe(SBIuI%jevh3`f^_iKOFV31Z>+$5|PGNnn^@yobY14gZ3N z?ceXwMMVzG1ECKYdw>bs(^EI11g>9ikluNko0_KU%1TQY6gYXu4(tk~Q52=H$+`80 z4ZrBf$@%rR`SY{ZW@KbMC*YR}_=O_{Z$~PUfF6T7kURK!SYo(JoJwAvOYFg)R838V z!jOW_gXi%S65tBI4+a~!ynLftxpJmL0e0{9h;&AJOB|}{hbvdSdj0z3KxXEzissFm zpF4N%+`s?7;A2T(B4WHp`EQySmKdkf+Un&E8@y`u>cwI${$+*~bY1`}s0|vnwe_$9 zZT$Yf@yeC=C@F~Q>A^fn=I(BHOrASCo%*%cTMJ*I-h3AyJosDbm1WxRU%}A%>go?P)TX$2IUhg1L^n207oJ-T@E0%MB@=vFOrF8{ zH{Nhcr+ncdt*l?bDD-sEtxC@l9^M zXOCAZpTYnylr%FX0^Vi7XJ*F0|7A3^xmlzpCSk9XaFsA-n4+);n6ScW!)r(-1mK-_ z+#;J6Capr{@g04Aq+fp>wE4-(k12RN;!nb+ld;5pza_>j*)%(ThY5=zg?@olLTw^% zEWGB8MFhMP;J2Xi85!dbJ~4?QJpoG$R|#Wgzj=tLS48I_l~9|ApZbwDag`qz+T1Ks zqm6B=lT2pp3l8Hd?KclNiA$GY{362-l!Dp_Z31y>^K4XYCJcNmiTIvCGZz&R!xF<) z+6nC1MG6xZL+bnQy-}&WcgtAm{AgoHPsoC=;pc-vkD(BZ8N3bbK_K9c4yhRU3FG`N zlZa02FkY|YH6r}HR3ED$-pb*0j6H~(uoKStTZQQf0X!fps98qf=V6J@o+TDz)(LMj z)heGDY1m=024a(HXh?#C)v&}lIro*pm_<21r7E8oY1m=024a(vWh4MUpPjvM{b*d} zL`NESSge8Aq_B+4n>X*pI|aNQGrZoEr?3XfwRZOG*^l2z;O(%m!(t5_3rjpHfd$;< na$$$P^T3aH{0{&C|NjF3Gs8gQWS}>Hh z#-=5uRaO&Uj2jy@eQ34&&=+4YF(EdMN>DLDi3xalQXeohUQ$uyqTmID-I<eMOU zjT<-g2M-?T&z?QgpFe-DkB*M&uU@^2wyWMUtf$SyFztFo@ z(YC!i$wNb(85tQzcI?>kkH_QDZr;494-5<#g1&k4W_sg{{rdIm>Fe0om_9x}Zrne4 z@5#NwF@r1-EPkBVP&7#<$h zuUxs}D=sd+NRFO7FTz9f5Wcgs({M@_9DX9xC2DOh1}a8U2+>e7meiVnEK}dhF0st!@qk~STPoLH( z5;iPav?w?$pgce%;196SD$PsESe^Oa9HF2XGlisYzzP6y|Necwyu7@FsPs`l;Zd0F z+qZ8R=41Mpd2hw}KmepauqCVj;2yyP0089p@#8}&DJk{g;o;GK0VE_Ol%O!6hUH5ʃjpZ@=A`Bi03zav6DRt!v$OZa#l@9` zSmgzDQs5q&^L_dN1Aszdfiq{$jICI)!bLRNMwLRi6@W?k0y6+yr9d+Q!1S3dfVQ?a z9{^A^s-|SCjz$#~6%%H2n)3iV@=Pei4jgPAP*JG8z1_Qf`EnN}wVH^ChdS?6kp5FeH88$UQwhzRjCA|4ezH zF*!MT8`W&qH4!DVzcIIwBM|v=b9WX901K{iTGbiO%h8AVf9~A5!MwaYS58jOcT}%! zqH-e25&$M<7&-+qH4m$-0N^(nD*a6*)r=_6vsP!ReO%!Ow{G3i)~{dxD{21+s)fpyELoCjDLgNX`!F#>XA~&h z1v&@&EITe}Bc1o)!Gn*W{oLH#uZSHRC<{9R0-&`P<39KTgIH()95xvM7;yFKRp08> ztA8iq_he*bR5%=t0%AyTQ;KEFmhHm04=?8IJR4dBdX|NkoQEZ-mDFl$YyTuRzz0pI+qodok{VHt-SliTSbsI4|QpYyaufr`n-IhgvCYx+wepNXe^=w4X|0 zen#?R*)Xd_laCK!gHm$^0KpM$xY{)H-sADyL)awhG!g%I#>dAO5%<+4bU*|)TXJb> zX?u5fx5o1tT-i5*r4S1b!J!CA8Kw<158+p?Ty}V?lS0&)pOHINg8T6w z9GIA?w8%oqExFD2d}cu8XNJR0alQ$fhww2mG3lYRA-_OqK8ErNar{-BdF*9Z$iJ9^)CPb0RR630Jsk4KL+Fo$p8QV M07*qoM6N<$f*SPmMgRZ+ literal 0 HcwPel00001 diff --git a/resources/old/5gem.png b/resources/old/5gem.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d100596d5d16c477cbd350529026706dcaa199 GIT binary patch literal 2413 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 Eg3;ujfdBvi literal 0 HcwPel00001 diff --git a/resources/old/7gem.png b/resources/old/7gem.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd9e49b0e11ac35d274d71fb2df1beba6d1aeb0 GIT binary patch literal 3274 zcwPa@3^ntKP)bW{)#X)|bujcTPSiXMy+V%zMd2x6C@ZVW|m z)tGq1O4-B~6=Ez{LBusHhA0e(AS!~045)NwfMFP#-23*u0qogqPP_eIXWzK5M7 zBMUuFpO?=#dmTJ}5fQx_3E`wtqFf~={N!R{aVP^ccE!oKz`z`C#E1w^Ma79ur}AG@ zTuDhu*~G-eY}BYxqg`EGTwPpUKXLK*KkjnowAk%o8TsITJ^3uZ1s4<&oS)xLJRV3; zASy@w!fG6m(MIgE3EEthqd`F};oZGQxbMHK;Oy*nay;JPH?BO7$5Xbju;7m$Ki=8J z+1cG?>eMio=;$JsigKLTASbi#N{L@y8~EoV_!lS&&dsd??`x&tcC`{5vk>jF5Lg*0 zYz5OC2~n$+5l&Q0xRon%IUOAzx{UH013-6vkTVsk{6uFTpPeq}&egli<;15_3X2P5 z@Yli)TzMB^*&Tod1)u=nmtG6L7ewHfRtsJ?DS)d0wzMdKWOm@-^m@=K76T`3B;5WV zYUv^YbSbshuDqtErZzR3F|Ksyoj>|0(j_%jKDDWZEWIy86cEDj^ky*5tpSxfdKxE=H+F$|y(eL1 zWo7Ncgqcl3V#D<6MiL}yA`vBkRCz_&a-Wc=o^iuHAR*`LaKjH}xcXcjF1X!6yl)Y- z?=&T(0Ek`Jvt8yR5C4O?etB)g2ui99`U8KXKc5pmK;yhV4VCVbKAv}CPHGV>EqH{RO7Izlp9ip+0@!xD84sM3!2Z~F z*mO_~OQ>>w)VbYrUIftHW+r8u`3Njd=A!N}r&G#2p3y4<3uyd~z0)MVU7M(n<{~G|ECjrAUT1elp?K0hdeV5Vb_i9ef zGOPwr3WriQH5@;t;Ag_gFoFD!^XRf5K-KY zn?;Xcv#8_A36ys3enep_9Q=m_6O$3*jv(yWkMK=w4KB!OhKae( z9qiKDaLA=<(8((UWr-BH=4Mn24lXw~GFqadtgO>x0D4A7p3YaU$lY36(X+S;KFOZBU6kqnNo<#l2UV_C0mL+vZb*7x)gT)S^@FLsxaZ03=VuJg}srq-}W*LJox~; z&WOSFXe~@QB1Vs&YGLw^Vwe(J3*!!oa7a=Km|l4RTDMAplQ$!ml++$k+aegh?;Z|4RSbsd z#n8K?7SyYysG4>S42O?Q=x=B^o%%wr9s$sPf6VTwDG$iJ{8lnAuN8f1S$so|o3f;2 z@2?GbB)Jh2lG^cXG9hQr6HKJfDL>R>RtzDj>j|cW5xhjpFJXklej&lour>@?M=*39 zA*;ih(RW=1&WNc**P}JW_EIAb&uGD6!e$(rAt&#hDtKSh za~mLRg%m>8BdiKq;UsHqs3~eLKY}n4n&m?&0!&b7@ z`vERmoQGr1h|xCt#XRu%ndJkzo?3n}(e?5Y3M?&G^y$;boob`;#{mo+xQxrm1@r8B zMXG1V>rCl@_bsH{2Eeb=oY*N~U~&ya?QMdXNEyVeEW_A2^>Ea?0}f1=!iKpe_|=#7 zurf>vlMhrWY`%Nz*jzDXOYY+}~p=`rMHacD(joVUHa*i`@<>GMEuvi3`Fj;L|MF(RB9RRbPzHDG^9_T+u{ z9hfOde`oJ~qN-qGOc6T8KVWxbczQmXfkB*f)xV>44A2*p&{UUX#dZOww6!7ke#)*!Zu=^ zQBQP>#HdkHjaHY+(B{-VVwcv+=)iCCeZ@0-Py4a{Y#bZU=3(=(d5yxNnv4fq#|^f& z{*vzge0_a=XC);i-B(w>Q^KoDeUX}Ofz{xo_ex8PpO?mrO?Zoq&*ZvTEUCzlgm zqYO04BsBENAKU!z13*Q8Hja%~%oBUCsqe^<3D#Ep5I%KWYC5whfn)c8p3&&v5oJzS zcMfmWsykds3DGa2(dlXjv1e?OW$UY*KG6OAe4F)S{n%^?r&^tJd;J6E{A<1Hvb=qii(OZpF literal 0 HcwPel00001 diff --git a/resources/pause.png b/resources/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..d6398b038e9f51578840152e734a2f300d94f076 GIT binary patch literal 206 zcwXxa@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|mUKs7M+S!VC(K#9UIO{8o-U3d z6?5KR*~oRsK&16yf7)f!b#@J9Wp9jso;kP6lU?`4Bn`I9N+ks^8jbJFnOwhP0!zN@ zn~euW%S+d8JS=AZ#nK|_fb!3#bxbdV=IwUgr7t$&jj$6V=gU2B_zHdqrEF(iv9?rt zja!+Z`m^b?1W))!IdH#t@9@{7Zr%)gliRP;+y1}cbg{A%Dah#C0dx?9r>mdKI;Vst E05zOY`~Uy| literal 0 HcwPel00001 diff --git a/resources/title.png b/resources/title.png new file mode 100644 index 0000000000000000000000000000000000000000..30da529609ddf781b6d2115b9a3b24d2a592ddf6 GIT binary patch literal 26272 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

>FM-(lnV&A;%wAw^g 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 O0000 + +@class Gem; + +@interface Game : NSObject +{ + // MW... + // + NSMutableArray *scoreBubbles; + // + Gem *board[8][8]; + int sx1,sy1,sx2,sy2, hintx, hinty; + int score, bonusMultiplier, gemsFaded; + // CASCADE BONUS + int cascade; + // + BOOL muted; +} + +- (id) init; +- (id) initWithImagesFrom:(NSArray *) imageArray; +- (id) initWithSpritesFrom:(NSArray *) spriteArray; +- (void) dealloc; + +- (void) setImagesFrom:(NSArray *) imageArray; +- (void) setSpritesFrom:(NSArray *) spriteArray; + +- (int) randomGemTypeAt:(int)x :(int)y; +- (Gem *) gemAt:(int)x :(int)y; +- (NSMutableArray *)scoreBubbles; + +- (void) setMuted:(BOOL)value; + +- (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2; +- (void) unswap; + +- (BOOL) testForThreeAt:(int) x :(int) y; +- (BOOL) checkForThreeAt:(int) x :(int) y; +- (BOOL) finalTestForThreeAt:(int) x :(int) y; +- (BOOL) checkBoardForThrees; +- (BOOL) boardHasMoves; +- (void) showAllBoardMoves; + +- (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray; +- (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray; +- (void) shake; +- (void) erupt; +- (void) explodeGameOver; +- (void) wholeNewGameWithImagesFrom:(NSArray *) imageArray; +- (void) wholeNewGameWithSpritesFrom:(NSArray *) spriteArray; + +- (NSPoint) hintPoint; +- (int) score; +- (float) collectGemsFaded; +- (int) bonusMultiplier; +- (void) increaseBonusMultiplier; + +@end diff --git a/src/Game.m b/src/Game.m new file mode 100644 index 0000000..f38ed9a --- /dev/null +++ b/src/Game.m @@ -0,0 +1,596 @@ +/* ----====----====----====----====----====----====----====----====----====---- +Game.m (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import "Game.h" +#import "Gem.h" +// +// MW... +// +#import "ScoreBubble.h" +// + +@implementation Game + +- (id) init +{ + int i,j; + self = [super init]; + gemsFaded = 0; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + board[i][j] = [[Gem alloc] init]; + // MW + scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain]; + // + return self; +} + +- (id) initWithImagesFrom:(NSArray *) imageArray +{ + int i,j; + self = [super init]; + srand([[NSDate date] timeIntervalSince1970]); // seed by time + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + int r = [self randomGemTypeAt:i:j]; + board[i][j] = [[Gem gemWithNumber:r andImage:[imageArray objectAtIndex:r]] retain]; + [board[i][j] setPositionOnBoard:i:j]; + [board[i][j] setPositionOnScreen:i*48:j*48]; + [board[i][j] shake]; + } + // MW... + scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain]; + // + score = 0; + gemsFaded = 0; + bonusMultiplier = 1; + return self; +} + +- (id) initWithSpritesFrom:(NSArray *) spriteArray +{ + int i,j; + self = [super init]; + srand([[NSDate date] timeIntervalSince1970]); // seed by time + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + //int r = (rand() % 3)*2+((i+j)%2); + int r = [self randomGemTypeAt:i:j]; + board[i][j] = [[Gem gemWithNumber:r andSprite:[spriteArray objectAtIndex:r]] retain]; + [board[i][j] setPositionOnBoard:i:j]; + [board[i][j] setPositionOnScreen:i*48:j*48]; + [board[i][j] shake]; + } + // MW... + scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain]; + // + score = 0; + gemsFaded = 0; + bonusMultiplier = 1; + return self; +} + +- (void) dealloc +{ + int i,j; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] release]; + // MW... + [scoreBubbles release]; + // + [super dealloc]; +} + +- (void) setImagesFrom:(NSArray *) imageArray +{ + int i,j; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] setImage:[imageArray objectAtIndex:[board[i][j] gemType]]]; +} + +- (void) setSpritesFrom:(NSArray *) spriteArray +{ + int i,j; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] setSprite:[spriteArray objectAtIndex:[board[i][j] gemType]]]; +} + +- (int) randomGemTypeAt:(int)x :(int)y +{ + int c = (x+y) % 2; + int r = rand() % 7; + if (c) + return (r & 6); // even + if (r == 6) + return 1; // catch returning 7 + return (r | 1); // odd +} + +- (Gem *) gemAt:(int)x :(int)y +{ + return board[x][y]; +} + +// +// MW... +// +- (NSMutableArray *)scoreBubbles +{ + return scoreBubbles; +} +// +//// + +- (void) setMuted:(BOOL)value +{ + int i,j; + muted = value; + if (muted) + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] setSoundsTink:NULL Sploink:NULL]; + else + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]]; +} + + +- (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2 +{ + Gem *swap = board[x1][y1]; + board[x1][y1] = board[x2][y2]; + [board[x1][y1] setPositionOnBoard:x1:y1]; + board[x2][y2] = swap; + [board[x2][y2] setPositionOnBoard:x2:y2]; + sx1 = x1; sx2 = x2; sy1 = y1; sy2 = y2; +} + +- (void) unswap +{ + [self swap:sx1:sy1 and:sx2:sy2]; +} + +- (BOOL) testForThreeAt:(int) x :(int) y +{ + int tx,ty,cx,cy; + int bonus, linebonus, scorePerGem; + float scorebubble_x = -1.0; + float scorebubble_y = -1.0; + BOOL result = NO; + int gemtype = [board[x][y] gemType]; + tx = x; ty = y; cx = x; cy = y; + bonus = 0; + if ([board[x][y] state] == GEMSTATE_FADING) result = YES; + while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1; + while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1; + if ((cx-tx) >= 2) + { + // horizontal line + int i,j; + linebonus= 0; + scorePerGem = (cx-tx)*5; + for (i = tx; i <= cx; i++) + { + linebonus+= scorePerGem; + [board[i][y] fade]; + for (j=7; j>y; j--) { + if ([board[i][j] state]!= GEMSTATE_FADING) { + [board[i][j] shiver]; // MW prepare to fall + } + } + } + // to center scorebubble ... + scorebubble_x = tx + (cx-tx)/2.0; + scorebubble_y = y; + // + bonus += linebonus; + result = YES; + } + while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1; + while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1; + if ((cy-ty) >= 2) + { + // vertical line + int i,j; + linebonus= 0; + scorePerGem = (cy-ty)*5; + for (i = ty; i <= cy; i++) + { + linebonus += scorePerGem; + [board[x][i] fade]; + } + for (j=7; j>cy; j--) { + if ([board[x][j] state]!= GEMSTATE_FADING) { + [board[x][j] shiver]; // MW prepare to fall + } + } + // to center scorebubble ... + if (scorebubble_x < 0) // only if one hasn't been placed already ! (for T and L shapes) + { + scorebubble_x = x; + scorebubble_y = ty + (cy-ty)/2.0; + } + else // select the original gem position + { + scorebubble_x = x; + scorebubble_y = y; + } + // + bonus += linebonus; + result = YES; + } + // CASCADE BONUS + if (cascade>=1) + bonus *= cascade; + // + // MW's scorebubble + // + if (bonus>0) + [scoreBubbles addObject:[ScoreBubble scoreWithValue:bonus*bonusMultiplier + At:NSMakePoint(scorebubble_x*48+24, scorebubble_y*48+24) + Duration:40]]; + // + score += bonus * bonusMultiplier; + return result; +} + +- (BOOL) finalTestForThreeAt:(int) x :(int) y +{ + int tx,ty,cx,cy; + BOOL result = NO; + int gemtype = [board[x][y] gemType]; + tx = x; ty = y; cx = x; cy = y; + + if ([board[x][y] state] == GEMSTATE_FADING) return YES; + + while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1; + while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1; + if ((cx-tx) >= 2) + { + // horizontal line + int i; + for (i = tx; i <= cx; i++) + [board[i][y] fade]; + result = YES; + } + while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1; + while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1; + if ((cy-ty) >= 2) + { + // vertical line + int i; + for (i = ty; i <= cy; i++) + [board[x][i] fade]; + result = YES; + } + return result; +} + +- (BOOL) checkForThreeAt:(int) x :(int) y +{ + int tx,ty,cx,cy; + int gemtype = [board[x][y] gemType]; + tx = x; ty = y; cx = x; cy = y; + while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1; + while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1; + if ((cx-tx) >= 2) + return YES; + while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1; + while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1; + if ((cy-ty) >= 2) + return YES; + return NO; +} + +- (BOOL) checkBoardForThrees +{ + int i,j; + BOOL result = NO; + // CASCADE BONUS increase + cascade++; + // + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + if ([board[i][j] state]!=GEMSTATE_FADING) + result = result | [self testForThreeAt:i:j]; + // CASCADE BONUS check for reset + if (!result) cascade = 1; + return result; +} + + +- (void) showAllBoardMoves +{ + // test every possible move + int i,j; + + // horizontal moves + for (j = 0; j < 8; j++) + for (i = 0; i < 7; i++) + { + [self swap:i:j and:i+1:j]; + [self finalTestForThreeAt:i:j]; + [self finalTestForThreeAt:i+1:j]; + [self unswap]; + } + + // vertical moves + for (i = 0; i < 8; i++) + for (j = 0; j < 7; j++) + { + [self swap:i:j and:i:j+1]; + [self finalTestForThreeAt:i:j]; + [self finalTestForThreeAt:i:j+1]; + [self unswap]; + } + + // over the entire board, set the animationtime for the marked gems higher + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + if ([board[i][j] state] == GEMSTATE_FADING) + { + [board[i][j] erupt]; + [board[i][j] setAnimationCounter:1]; + } + else + [board[i][j] erupt]; + } + + +} + +- (BOOL) boardHasMoves +{ + // test every possible move + int i,j; + BOOL result = NO; + // horizontal moves + for (j = 0; j < 8; j++) + for (i = 0; i < 7; i++) + { + [self swap:i:j and:i+1:j]; + result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i+1:j]; + [self unswap]; + if (result) + { + hintx = i; + hinty = j; + return result; + } + } + + // vertical moves + for (i = 0; i < 8; i++) + for (j = 0; j < 7; j++) + { + [self swap:i:j and:i:j+1]; + result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i:j+1]; + [self unswap]; + if (result) + { + hintx = i; + hinty = j; + return result; + } + } + return NO; +} + +- (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray +{ + int i,j,fades, y; + for (i = 0; i < 8; i++) + { + Gem *column[8]; + fades = 0; + y = 0; + // let non-faded gems fall into place + for (j = 0; j < 8; j++) + { + if ([board[i][j] state] != GEMSTATE_FADING) + { + column[y] = board[i][j]; + if ([board[i][j] positionOnScreen].y > y*48) + [board[i][j] fall]; + y++; + } + else + fades++; + } + // transfer faded gems to top of column + for (j = 0; j < 8; j++) + { + if ([board[i][j] state] == GEMSTATE_FADING) + { + // randomly reassign + int r = (rand() % 7); + [board[i][j] setGemType:r]; + [board[i][j] setImage:[imageArray objectAtIndex:r]]; + + column[y] = board[i][j]; + [board[i][j] setPositionOnScreen:i*48:(7+fades)*48]; + [board[i][j] fall]; + y++; + gemsFaded++; + fades--; + } + } + // OK, shuffling all done - reorganise column + for (j = 0; j < 8; j++) + { + board[i][j] = column[j]; + [board[i][j] setPositionOnBoard:i:j]; + } + } +} + +- (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray +{ + int i,j,fades, y; + for (i = 0; i < 8; i++) + { + Gem *column[8]; + fades = 0; + y = 0; + // let non-faded gems fall into place + for (j = 0; j < 8; j++) + { + if ([board[i][j] state] != GEMSTATE_FADING) + { + column[y] = board[i][j]; + if ([board[i][j] positionOnScreen].y > y*48) + [board[i][j] fall]; + y++; + } + else + fades++; + } + // transfer faded gems to top of column + for (j = 0; j < 8; j++) + { + if ([board[i][j] state] == GEMSTATE_FADING) + { + // randomly reassign + int r = (rand() % 7); + [board[i][j] setGemType:r]; + [board[i][j] setSprite:[spriteArray objectAtIndex:r]]; + + column[y] = board[i][j]; + [board[i][j] setPositionOnScreen:i*48:(7+fades)*48]; + [board[i][j] fall]; + y++; + gemsFaded++; + fades--; + } + } + // OK, shuffling all done - reorganise column + for (j = 0; j < 8; j++) + { + board[i][j] = column[j]; + [board[i][j] setPositionOnBoard:i:j]; + } + } +} + +- (void) shake +{ + int i,j; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] shake]; +} + +- (void) erupt +{ + int i,j; + if (!muted) [[NSSound soundNamed:@"yes"] play]; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] erupt]; +} + +- (void) explodeGameOver +{ + //int i,j; + if (!muted) [[NSSound soundNamed:@"explosion"] play]; + /*-- + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [board[i][j] erupt]; + --*/ + [self showAllBoardMoves]; // does a delayed eruption +} + +- (void) wholeNewGameWithImagesFrom:(NSArray *) imageArray +{ + int i,j; + srand([[NSDate date] timeIntervalSince1970]); // seed by time + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + //int r = (rand() % 3)*2+((i+j)%2); + int r = [self randomGemTypeAt:i:j]; + [board[i][j] setGemType:r]; + [board[i][j] setImage:[imageArray objectAtIndex:r]]; + [board[i][j] setPositionOnBoard:i:j]; + [board[i][j] setPositionOnScreen:i*48:(15-j)*48]; + [board[i][j] fall]; + } + score = 0; + gemsFaded = 0; + bonusMultiplier = 1; +} + +- (void) wholeNewGameWithSpritesFrom:(NSArray *) spriteArray +{ + int i,j; + srand([[NSDate date] timeIntervalSince1970]); // seed by time + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + //int r = (rand() % 3)*2+((i+j)%2); + int r = [self randomGemTypeAt:i:j]; + [board[i][j] setGemType:r]; + [board[i][j] setSprite:[spriteArray objectAtIndex:r]]; + [board[i][j] setPositionOnBoard:i:j]; + [board[i][j] setPositionOnScreen:i*48:(15-j)*48]; + [board[i][j] fall]; + } + score = 0; + gemsFaded = 0; + bonusMultiplier = 1; +} + +- (NSPoint) hintPoint +{ + return NSMakePoint(hintx*48,hinty*48); +} + +- (float) collectGemsFaded +{ + float result = (float)gemsFaded; + gemsFaded = 0; + return result; +} + +- (int) score +{ + return score; +} + +- (int) bonusMultiplier +{ + return bonusMultiplier; +} + +- (void) increaseBonusMultiplier +{ + bonusMultiplier++; +} + +@end diff --git a/src/GameController.h b/src/GameController.h new file mode 100644 index 0000000..63f6c21 --- /dev/null +++ b/src/GameController.h @@ -0,0 +1,147 @@ +/* ----====----====----====----====----====----====----====----====----====---- +GameController.h (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import + +#define GAMESTATE_GAMEOVER 1 +#define GAMESTATE_AWAITINGFIRSTCLICK 2 +#define GAMESTATE_AWAITINGSECONDCLICK 3 +#define GAMESTATE_FRACULATING 4 +#define GAMESTATE_SWAPPING 5 +#define GAMESTATE_FADING 6 +#define GAMESTATE_FALLING 7 +#define GAMESTATE_UNSWAPPING 8 +#define GAMESTATE_EXPLODING 9 +#define GAMESTATE_FINISHEDFRACULATING 10 + +#define GEM_GRAPHIC_SIZE 48 +#define GEM_MOVE_SPEED 6 + +#define GEMS_FOR_BONUS 100.0 +#define SPEED_LIMIT 5000 + +#define TIMER_INTERVAL 0.04 + +@class Game, GameView, MyTimerView; + +@interface GameController : NSObject +{ + IBOutlet NSPanel *aboutPanel, *prefsPanel; + IBOutlet GameView *gameView; + IBOutlet NSButton *prefsStandardGraphicsButton, *prefsAlternateGraphicsButton; + IBOutlet NSImageView *prefsAlternateGraphicsImageView; + IBOutlet NSButton *prefsCustomBackgroundCheckbox, *prefsSelectFolderButton; + IBOutlet NSTextField *prefsCustomBackgroundFolderTextField; + IBOutlet NSImageView *iv1, *iv2, *iv3, *iv4, *iv5, *iv6, *iv7; + IBOutlet NSButton *easyGameButton, *hardGameButton, *toughGameButton; + IBOutlet NSMenuItem *easyGameMenuItem, *hardGameMenuItem, *toughGameMenuItem; + IBOutlet NSButton *abortGameButton, *pauseGameButton, *muteButton; + IBOutlet NSMenuItem *abortGameMenuItem, *pauseGameMenuItem, *muteMenuItem; + IBOutlet NSMenuItem *freePlayMenuItem, *showHighScoresMenuItem, *resetHighScoresMenuItem; + IBOutlet NSTextField *scoreTextField, *bonusTextField; + IBOutlet MyTimerView *timerView; + IBOutlet NSWindow *gameWindow; + IBOutlet NSPanel *hiScorePanel; + IBOutlet NSTextField *hiScorePanelScoreTextField, *hiScorePanelNameTextField; + + NSLock *animationTimerLock; + + NSArray *hiScores; + NSMutableArray *gameScores, *gameNames; + + int *hintTimeSeconds; + + NSString *noMoreMovesString, *jeweltoyStartString, *gameOverString; + NSImage *titleImage; + + BOOL abortGame; + NSTimer *timer; + Game *game; + int gameLevel; + float gameSpeed; + float gameTime; + int gemMoveSpeed, gemMoveSteps, gemMoveSize; + + BOOL useAlternateGraphics, useImportedGraphics, useCustomBackgrounds; + BOOL paused, freePlay, muted, animationStatus; + + NSString *customBackgroundFolderPath; + + int gameState, gemsSoFar, chx1, chy1, chx2, chy2; + SEL whatNext; +} + +- (id) init; +- (void) dealloc; + +- (void)awakeFromNib; + +- (void)windowWillClose:(NSNotification *)aNotification; +- (IBAction)prefsGraphicDropAction:(id)sender; +- (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender; +- (IBAction)prefsSelectFolderButtonAction:(id)sender; + +- (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem; + +- (IBAction)startNewGame:(id)sender; +- (IBAction)abortGame:(id)sender; +- (IBAction)receiveHiScoreName:(id)sender; +- (IBAction)togglePauseMode:(id)sender; +- (IBAction)toggleMute:(id)sender; +- (IBAction)orderFrontAboutPanel:(id)sender; +- (IBAction)orderFrontPreferencesPanel:(id)sender; +- (IBAction)showHighScores:(id)sender; +- (IBAction)resetHighScores:(id)sender; + +- (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores; + +- (void)runOutOfTime; +- (void)checkHiScores; +- (void)bonusAwarded; + +- (void)startAnimation:(SEL)andThenSelector; +- (void)animationEnded; + +- (void)waitForNewGame; +- (void)newBoard1; +- (void)newBoard2; +- (void)waitForFirstClick; +- (void)receiveClickAt:(int)x:(int)y; +- (void)tryMoveSwapping:(int)x1:(int)y1 and:(int)x2:(int)y2; + // test for threes +- (void)testForThrees; + // if there are threes: + + //// repeat: remove threes +- (void)removeThreesAndReplaceGems; + //// replace gems +- (void)testForThreesAgain; + //// test for threes + //// until there are no threes +- (void)unSwap; + // else swap them back + +- (int) gameState; +- (BOOL) gameIsPaused; +- (BOOL) useCustomBackgrounds; +- (NSPoint) crossHair1Position; +- (NSPoint) crossHair2Position; +@end diff --git a/src/GameController.m b/src/GameController.m new file mode 100644 index 0000000..0d74bd3 --- /dev/null +++ b/src/GameController.m @@ -0,0 +1,862 @@ +/* ----====----====----====----====----====----====----====----====----====---- +GameController.m (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import "GameController.h" +#import "MyTimerView.h" +#import "Game.h" +#import "GameView.h" +#import "Gem.h" + +@implementation GameController + +- (id) init +{ + self = [super init]; + + hiScores = [[NSUserDefaults standardUserDefaults] arrayForKey:@"hiScores"]; + + //NSLog(@"hiScores : %@",hiScores); + + if ((!hiScores)||([hiScores count] < 8)) + { + //NSLog(@"Creating High Score Tables"); + hiScores = [self makeBlankHiScoresWith:hiScores]; + [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"]; + } + [hiScores retain]; + + noMoreMovesString = [[NSBundle mainBundle] + localizedStringForKey:@"NoMoreMovesHTML" + value:nil table:nil]; + jeweltoyStartString = [[NSBundle mainBundle] + localizedStringForKey:@"JewelToyStartHTML" + value:nil table:nil]; + gameOverString = [[NSBundle mainBundle] + localizedStringForKey:@"GameOverHTML" + value:nil table:nil]; + titleImage = [NSImage imageNamed:@"title"]; + gameLevel = 0; + gameNames = [hiScores objectAtIndex:0]; + gameScores = [hiScores objectAtIndex:1]; + + game = [[Game alloc] init]; + animationTimerLock = [[NSLock alloc] init]; + + gemMoveSize = GEM_GRAPHIC_SIZE; + gemMoveSpeed = GEM_MOVE_SPEED; + gemMoveSteps = gemMoveSize / gemMoveSpeed; + + useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"]; + useImportedGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useImportedGraphics"]; + + useCustomBackgrounds = [[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"]; + customBackgroundFolderPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"]; + if (!customBackgroundFolderPath) + customBackgroundFolderPath = [[NSBundle mainBundle] localizedStringForKey:@"PicturesFolderPath" + value:nil table:nil]; + return self; +} + +- (void) dealloc +{ + if (noMoreMovesString) [noMoreMovesString release]; + if (jeweltoyStartString) [jeweltoyStartString release]; + if (gameOverString) [gameOverString release]; + if (game) [game release]; + if (animationTimerLock) [animationTimerLock release]; + if (timer) [timer release]; + if (hiScores) [hiScores release]; + [super dealloc]; +} + +- (void)awakeFromNib +{ + [gameWindow setFrameAutosaveName:@"gameWindow"]; + //useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"]; +} + +- (void)windowWillClose:(NSNotification *)aNotification +{ + id obj = [aNotification object]; + if (obj == aboutPanel) + { + //NSLog(@"Someone closed the 'About' window"); + aboutPanel = nil; + return; + } + if (obj == prefsPanel) + { + //NSLog(@"Someone closed the 'Preferences' window"); + useAlternateGraphics = [prefsAlternateGraphicsButton state]; + [[NSUserDefaults standardUserDefaults] setBool:useAlternateGraphics + forKey:@"useAlternateGraphics"]; + [[NSUserDefaults standardUserDefaults] setBool:useImportedGraphics + forKey:@"useImportedGraphics"]; + + useCustomBackgrounds = [prefsCustomBackgroundCheckbox state]; + [[NSUserDefaults standardUserDefaults] setBool:useCustomBackgrounds + forKey:@"useCustomBackgrounds"]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"customBackgroundFolderPath"]; + [[NSUserDefaults standardUserDefaults] setObject:[prefsCustomBackgroundFolderTextField stringValue] + forKey:@"customBackgroundFolderPath"]; + if (gameView) + { + //[gameView loadImageArray]; + [gameView graphicSetUp]; + [gameView newBackground]; + if (game) [game setSpritesFrom:[gameView spriteArray]]; + [gameView setNeedsDisplay:YES]; + } + prefsPanel = nil; + return; + } + if (obj == gameWindow) + { + //NSLog(@"Someone closed the window - shutting down JewelToy"); + [NSApp terminate:self]; + return; + } +} + +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + [prefsCustomBackgroundFolderTextField setStringValue:[[sheet filenames] objectAtIndex:0]]; +} + +- (IBAction)prefsGraphicDropAction:(id)sender +{ + // + // slice and dice importedImage, saving images to defaults + // + NSImage *importedImage = [prefsAlternateGraphicsImageView image]; + if (importedImage) + { + int i = 0; + NSRect cropRect = NSMakeRect(0.0,0.0,[importedImage size].width/7.0,[importedImage size].height); + NSRect gemRect = NSMakeRect(0.0,0.0,48.0,48.0); + NSSize imageSize = NSMakeSize(48.0,48.0); + for (i = 0; i < 7; i++) + { + NSImage *gemImage = [[NSImage alloc] initWithSize:imageSize]; + NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i]; + cropRect.origin.x = i * [importedImage size].width/7.0; + [gemImage lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(gemRect); + [importedImage drawInRect:gemRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0]; + [gemImage unlockFocus]; + [[NSUserDefaults standardUserDefaults] setObject:[gemImage TIFFRepresentation] forKey:key]; + if (i == 0) [iv1 setImage:gemImage]; + if (i == 1) [iv2 setImage:gemImage]; + if (i == 2) [iv3 setImage:gemImage]; + if (i == 3) [iv4 setImage:gemImage]; + if (i == 4) [iv5 setImage:gemImage]; + if (i == 5) [iv6 setImage:gemImage]; + if (i == 6) [iv7 setImage:gemImage]; + [gemImage release]; + } + useImportedGraphics = YES; + } + +} + +- (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender +{ + //NSLog(@"prefsCustomBackgroundCheckboxAction"); + + if (sender!=prefsCustomBackgroundCheckbox) + return; + [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]]; + [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]]; + +} + +- (IBAction)prefsSelectFolderButtonAction:(id)sender +{ + NSOpenPanel *op=[NSOpenPanel openPanel]; + + //NSLog(@"prefsSelectFolderButtonAction"); + [op setCanChooseDirectories:YES]; + [op setCanChooseFiles:NO]; + // get a sheet going to let the user pick a folder to scan for pictures + [op beginSheetForDirectory:[prefsCustomBackgroundFolderTextField stringValue] file:NULL types:NULL modalForWindow:prefsPanel modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; +} + + +- (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem +{ + if (aMenuItem == easyGameMenuItem) + return [easyGameButton isEnabled]; + if (aMenuItem == hardGameMenuItem) + return [hardGameButton isEnabled]; + if (aMenuItem == toughGameMenuItem) + return [toughGameButton isEnabled]; + if (aMenuItem == freePlayMenuItem) + return [easyGameButton isEnabled]; + if (aMenuItem == abortGameMenuItem) + return [abortGameButton isEnabled]; + if (aMenuItem == pauseGameMenuItem) + return [pauseGameButton isEnabled]; + // + // only allow viewing and reset of scores between games + // + if (aMenuItem == showHighScoresMenuItem) + return [easyGameButton isEnabled]; + if (aMenuItem == resetHighScoresMenuItem) + return [easyGameButton isEnabled]; + return YES; +} + +- (IBAction)startNewGame:(id)sender +{ + //NSLog(@"gameController.startNewGame messaged gameView:%@",gameView); + + [easyGameButton setEnabled:NO]; + [hardGameButton setEnabled:NO]; + [toughGameButton setEnabled:NO]; + [abortGameButton setEnabled:YES]; + [pauseGameButton setEnabled:YES]; + + abortGame = NO; + gameSpeed = 1.0; + gameLevel = 0; + + if ((sender==easyGameButton)||(sender==easyGameMenuItem)) + { + //NSLog(@"debug - hiScores = %@\n...hiScores.count = %d",hiScores,[hiScores count]); + gameLevel = 0; + gameTime = 600.0; // ten minutes + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"EasyHighScoresHTML" + value:nil table:nil]]; + } + if ((sender==hardGameButton)||(sender==hardGameMenuItem)) + { + gameLevel = 1; + gameTime = 180.0; // three minutes + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"HardHighScoresHTML" + value:nil table:nil]]; + + } + if ((sender==toughGameButton)||(sender==toughGameMenuItem)) + { + gameLevel = 2; + gameTime = 90.0; // one and a half minutes + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"ToughHighScoresHTML" + value:nil table:nil]]; + } + if (sender==freePlayMenuItem) + { + gameLevel = 3; + gameTime = 3600.0; // one hour FWIW + freePlay = YES;// FREEPLAY + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"FreePlayHighScoresHTML" + value:nil table:nil]]; + } + else + freePlay = NO;// FREEPLAY + gameNames = [hiScores objectAtIndex:gameLevel*2]; + gameScores = [hiScores objectAtIndex:gameLevel*2+1]; + [game wholeNewGameWithSpritesFrom:[gameView spriteArray]]; + +// + [scoreTextField setStringValue:[NSString stringWithFormat:@"%d",[game score]]]; + [scoreTextField setNeedsDisplay:YES]; + [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d",[game bonusMultiplier]]]; + [bonusTextField setNeedsDisplay:YES]; +// + + [game setMuted:muted]; + [gameView setGame:game]; + [gameView setLegend:nil]; + [gameView setPaused:NO]; + [gameView setMuted:muted]; + [gameView setShowHint:!freePlay];// FREEPLAY + + [timerView setTimerRunningEvery:0.5/gameSpeed + decrement:(0.5/gameTime) + withTarget:self + whenRunOut:@selector(runOutOfTime) + whenRunOver:@selector(bonusAwarded)]; + + if (freePlay) + { + [timerView setDecrement:0.0];// FREEPLAY MW + [timerView setTimer:0.0]; + } + + [timerView setPaused:YES]; + + [gameView setLastMoveDate]; + [self startAnimation:@selector(waitForFirstClick)]; +} + +- (IBAction)abortGame:(id)sender +{ + [abortGameButton setEnabled:NO]; + if (paused) [self togglePauseMode:self]; + [pauseGameButton setEnabled:NO]; + abortGame = YES; + [self waitForFirstClick]; +} +- (IBAction)receiveHiScoreName:(id)sender +{ + int i; + int score = [hiScorePanelScoreTextField intValue]; + NSString *name = [hiScorePanelNameTextField stringValue]; + + [NSApp endSheet:hiScorePanel]; + [hiScorePanel close]; + + //NSLog(@"receiving HiScoreName:%@ %d",name,score); + + // reset arrays to gameLevel + gameNames = [hiScores objectAtIndex:gameLevel*2]; + gameScores = [hiScores objectAtIndex:gameLevel*2+1]; + + for (i = 0; i < 10; i++) + { + if (score > [[gameScores objectAtIndex:i] intValue]) + { + [gameScores insertObject:[NSNumber numberWithInt:score] atIndex:i]; + [gameScores removeObjectAtIndex:10]; + [gameNames insertObject:name atIndex:i]; + [gameNames removeObjectAtIndex:10]; + break; + } + } + + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hiScores"]; // or it won't work!?! + [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"]; + + //NSLog(@"written high-scores to preferences"); + + gameState = GAMESTATE_GAMEOVER; + [gameView showHighScores:gameScores andNames:gameNames]; + [gameView setLastMoveDate]; //reset timer so scores show for 20s +} + +- (IBAction)togglePauseMode:(id)sender +{ + //NSLog(@"Pause game toggled, sender state is %d",[sender state]); + if (sender == pauseGameButton) + paused = [sender state]; + else + paused = !paused; + + [pauseGameButton setState:paused]; + [timerView setPaused:paused]; + if (paused) + { + [gameView setPaused:YES]; + [gameView setHTMLLegend:[[NSBundle mainBundle] + localizedStringForKey:@"PausedHTML" + value:nil table:nil]]; + [pauseGameMenuItem setTitle:[[NSBundle mainBundle] + localizedStringForKey:@"ContinueGameMenuItemTitle" + value:nil table:nil]]; + } + else + { + [gameView setPaused:NO]; + [gameView setLegend:nil]; + [pauseGameMenuItem setTitle:[[NSBundle mainBundle] + localizedStringForKey:@"PauseGameMenuItemTitle" + value:nil table:nil]]; + } +} + +- (IBAction)toggleMute:(id)sender +{ + if (sender == muteButton) + muted = [sender state]; + else + muted = !muted; + + [muteButton setState:muted]; + [gameView setMuted:muted]; + [game setMuted:muted]; + + if (muted) + [muteMenuItem setTitle:[[NSBundle mainBundle] + localizedStringForKey:@"UnMuteGameMenuItemTitle" + value:nil table:nil]]; + else + [muteMenuItem setTitle:[[NSBundle mainBundle] + localizedStringForKey:@"MuteGameMenuItemTitle" + value:nil table:nil]]; + +} + +- (IBAction)orderFrontAboutPanel:(id)sender +{ + //NSLog(@"GameController showAboutPanel called"); + if (!aboutPanel) + [NSBundle loadNibNamed:@"About" owner:self]; + [aboutPanel setFrameAutosaveName:@"aboutPanel"]; + [aboutPanel makeKeyAndOrderFront:self]; +} + +- (IBAction)orderFrontPreferencesPanel:(id)sender +{ + if (!prefsPanel) + [NSBundle loadNibNamed:@"Preferences" owner:self]; + + [prefsStandardGraphicsButton setState:!useAlternateGraphics]; + [prefsAlternateGraphicsButton setState:useAlternateGraphics]; + + [prefsCustomBackgroundCheckbox setState:useCustomBackgrounds]; + [prefsCustomBackgroundFolderTextField setStringValue:customBackgroundFolderPath]; + [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]]; + [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]]; + + if ([[NSUserDefaults standardUserDefaults] dataForKey:@"tiffGemImage0"]) + { // set up images! + int i = 0; + for (i = 0; i < 7; i++) + { + NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i]; + NSData *tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:key]; + NSImage *gemImage = [[NSImage alloc] initWithData:tiffData]; + if (i == 0) [iv1 setImage:gemImage]; + if (i == 1) [iv2 setImage:gemImage]; + if (i == 2) [iv3 setImage:gemImage]; + if (i == 3) [iv4 setImage:gemImage]; + if (i == 4) [iv5 setImage:gemImage]; + if (i == 5) [iv6 setImage:gemImage]; + if (i == 6) [iv7 setImage:gemImage]; + [gemImage release]; + } + } + + [prefsPanel setFrameAutosaveName:@"prefsPanel"]; + [prefsPanel makeKeyAndOrderFront:self]; +} + +- (IBAction)showHighScores:(id)sender +{ + // rotate which scores to show + // + gameNames = [hiScores objectAtIndex:gameLevel*2]; + gameScores = [hiScores objectAtIndex:gameLevel*2+1]; + if (gameLevel==0) + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"EasyHighScoresHTML" + value:nil table:nil]]; + else if (gameLevel==1) + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"HardHighScoresHTML" + value:nil table:nil]]; + else if (gameLevel==2) + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"ToughHighScoresHTML" + value:nil table:nil]]; + else if (gameLevel==3) + [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle] + localizedStringForKey:@"FreePlayHighScoresHTML" + value:nil table:nil]]; + gameLevel = (gameLevel +1)%4; + + [gameView showHighScores:gameScores andNames:gameNames]; + [gameView setLastMoveDate]; //reset timer so scores show for 20s +} + +- (IBAction)resetHighScores:(id)sender +{ + // don't rotate which scores to show + // + // blank the hi scores + // + [hiScores release]; + hiScores = [[self makeBlankHiScoresWith:nil] retain]; + [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"]; + + [self showHighScores:sender]; //call the show scores routine +} + +- (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores +{ + //int i,j; + int j; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:0]; + + if (oldScores) result = [NSMutableArray arrayWithArray:oldScores]; + + //for (i = 0; i < 3; i++) + while ([result count] < 8) + { + NSMutableArray *scores = [NSMutableArray arrayWithCapacity:0]; + NSMutableArray *names = [NSMutableArray arrayWithCapacity:0]; + for (j = 0; j < 10; j++) + { + [scores addObject:[NSNumber numberWithInt:1000]]; + [names addObject:[[NSBundle mainBundle] + localizedStringForKey:@"AnonymousName" + value:nil table:nil]]; + } + [result addObject:names]; + [result addObject:scores]; + } + return [NSArray arrayWithArray:result]; +} + +- (void)runOutOfTime +{ + gameState = GAMESTATE_GAMEOVER; + [abortGameButton setEnabled:NO]; + [pauseGameButton setEnabled:NO]; + abortGame = YES; + [gameView setHTMLLegend:gameOverString]; + [game shake]; + [self startAnimation:@selector(waitForFirstClick)]; +} + +- (void)checkHiScores +{ + int i; + // reset arrays with gameLevel + gameNames = [hiScores objectAtIndex:gameLevel*2]; + gameScores = [hiScores objectAtIndex:gameLevel*2+1]; + for (i = 0; i < 10; i++) + { + if ([game score] > [[gameScores objectAtIndex:i] intValue]) + { + [hiScorePanelScoreTextField + setStringValue:[NSString stringWithFormat:@"%d",[game score]]]; + [NSApp beginSheet:hiScorePanel + modalForWindow:gameWindow + modalDelegate:self + didEndSelector:NULL + contextInfo:NULL]; + return; + } + } + [gameView showHighScores:gameScores andNames:gameNames]; +} + +- (void)bonusAwarded +{ + + [gameView newBackground]; + + if (!muted) [[NSSound soundNamed:@"yes"] play]; + + if (!freePlay) { // FREEPLAY MW + [game increaseBonusMultiplier]; + [timerView decrementMeter:0.5]; + } else { + [game increaseBonusMultiplier]; + [timerView decrementMeter:1]; + } + + if (gameSpeed < SPEED_LIMIT) // capping speed limit + gameSpeed = gameSpeed * 1.5; + //NSLog(@"...gamesSpeed %f",gameSpeed); + [timerView setTimerRunningEvery:0.5/gameSpeed + decrement:(0.5/gameTime) + withTarget:self + whenRunOut:@selector(runOutOfTime) + whenRunOver:@selector(bonusAwarded)]; + + if (freePlay) [timerView setDecrement:0];// FREEPLAY +} + +- (void)startAnimation:(SEL)andThenSelector; +{ + [animationTimerLock lock]; + // + if (!timer) + timer = [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL + target:gameView + selector:@selector(animate) + userInfo:self + repeats:YES] retain]; + // + whatNext = andThenSelector; + // + [gameView setAnimating:YES]; + // + [animationTimerLock unlock]; +} + +- (void)animationEnded +{ + //NSLog(@"gameController.animationEnded messaged"); + + [animationTimerLock lock]; + // + [gameView setAnimating:NO]; + // + [animationTimerLock unlock]; + + if (whatNext) [self performSelector:whatNext]; + + [gameView setNeedsDisplay:YES]; +} + +- (void)waitForNewGame +{ + [self checkHiScores]; + + [game wholeNewGameWithSpritesFrom:[gameView spriteArray]]; + [gameView setLegend:titleImage]; + [easyGameButton setEnabled:YES]; + [hardGameButton setEnabled:YES]; + [toughGameButton setEnabled:YES]; + [abortGameButton setEnabled:NO]; + [pauseGameButton setEnabled:NO]; +} + +- (void)newBoard1 +{ + //NSLog(@"newBoard1"); + [game erupt]; + [self startAnimation:@selector(newBoard2)]; +} + +- (void)newBoard2 +{ + Gem *gem; + int i,j,r; + //NSLog(@"newBoard2"); + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + gem = [game gemAt:i:j]; + //NSLog(@"..gem..%@",gem); + r = rand() % 7; + [gem setGemType:r]; + //[gem setImage:[[gameView imageArray] objectAtIndex:r]]; + [gem setSprite:[[gameView spriteArray] objectAtIndex:r]]; + [gem setPositionOnBoard:i:j]; + [gem setPositionOnScreen:i*48:(i+j+8)*48]; + [gem fall]; + } + } + [gameView newBackground]; + [gameView setLegend:nil]; + [self startAnimation:@selector(testForThreesAgain)]; +} + +- (void)waitForFirstClick +{ + //NSLog(@"waitForFirstClick"); + /*- if (!freePlay) MW CHANGE -*/ [timerView setPaused:NO]; + if (abortGame) + { + [timerView setTimer:0.5]; + gameState = GAMESTATE_GAMEOVER; + [game explodeGameOver]; + [self startAnimation:@selector(waitForNewGame)]; + return; + } + if (![game boardHasMoves]) + { + [timerView setPaused:YES]; + [gameView setHTMLLegend:noMoreMovesString]; + [game shake]; + + if (freePlay) [self startAnimation:@selector(runOutOfTime)];// FREEPLAY + else [self startAnimation:@selector(newBoard1)];// FREEPLAY + + return; + } + gameState = GAMESTATE_AWAITINGFIRSTCLICK; +} + +- (void)receiveClickAt:(int)x:(int)y +{ + if (paused) return; + if ((x < 0)||(x > 383)||(y < 0)||(y > 383)) return; + if (gameState == GAMESTATE_AWAITINGFIRSTCLICK) + { + chx1 = floor(x / 48); + chy1 = floor(y / 48); + gameState = GAMESTATE_AWAITINGSECONDCLICK; + [gameView setNeedsDisplay:YES]; + return; + } + if (gameState == GAMESTATE_AWAITINGSECONDCLICK) + { + chx2 = floor(x / 48); + chy2 = floor(y / 48); + if ((chx2 != chx1)^(chy2 != chy1)) // xor! + { + int d = (chx1-chx2)*(chx1-chx2)+(chy1-chy2)*(chy1-chy2); + //NSLog(@"square distance ==%d",d); + if (d==1) + { + gameState = GAMESTATE_FRACULATING; + [gameView setNeedsDisplay:YES]; + [gameView setLastMoveDate]; + /*- MW CHANGE if (!freePlay) -*/ [timerView setPaused:YES]; + [self tryMoveSwapping:chx1:chy1 and:chx2:chy2]; + return; + } + } + // fall out of routine setting first click location + chx1 = floor(x / 48); + chy1 = floor(y / 48); + gameState = GAMESTATE_AWAITINGSECONDCLICK; + [gameView setNeedsDisplay:YES]; + } +} + + +- (void)tryMoveSwapping:(int)x1:(int)y1 and:(int)x2:(int)y2 +{ + // do stuff here!!! + int xx1, yy1, xx2, yy2; + //NSLog(@"tryMoveSwapping"); + if (x1 != x2) + { + if (x1 < x2) { xx1 = x1; xx2 = x2; } + else { xx1 = x2; xx2 = x1; } + yy1 = y1; + yy2 = y2; + } + else + { + if (y1 < y2) { yy1 = y1; yy2 = y2; } + else { yy1 = y2; yy2 = y1; } + xx1 = x1; + xx2 = x2; + } + // store swap positions + chx1 = xx1; chy1 = yy1; chx2 = xx2; chy2 = yy2; + // swap positions + if (chx1 < chx2) // swapping horizontally + { + [[game gemAt:chx1:chy1] setVelocity:gemMoveSpeed:0:gemMoveSteps]; + [[game gemAt:chx2:chy2] setVelocity:-gemMoveSpeed:0:gemMoveSteps]; + } + else // swapping vertically + { + [[game gemAt:chx1:chy1] setVelocity:0:gemMoveSpeed:gemMoveSteps]; + [[game gemAt:chx2:chy2] setVelocity:0:-gemMoveSpeed:gemMoveSteps]; + } + [game swap:chx1:chy1 and:chx2:chy2]; + gameState = GAMESTATE_SWAPPING; + [self startAnimation:@selector(testForThrees)]; +} + + // test for threes +- (void)testForThrees +{ + BOOL anyThrees; + int oldScore = [game score]; + //NSLog(@"testForThrees"); + anyThrees = ([game testForThreeAt:chx1:chy1])|([game testForThreeAt:chx2:chy2]); + [scoreTextField setStringValue:[NSString stringWithFormat:@"%d",[game score]]]; + [scoreTextField setNeedsDisplay:YES]; + [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d",[game bonusMultiplier]]]; + [bonusTextField setNeedsDisplay:YES]; + if ([game score] > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS]; + if (anyThrees) + [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems + else + [self unSwap]; +} + + //// repeat: remove threes +- (void)removeThreesAndReplaceGems +{ + + //NSLog(@"removeThreesAndReplaceGems"); + // deal with fading + [game removeFadedGemsAndReorganiseWithSpritesFrom:[gameView spriteArray]]; + + [self startAnimation:@selector(testForThreesAgain)]; // gems fall down +} + +- (void)testForThreesAgain +{ + BOOL anyThrees; + int oldScore = [game score]; + //NSLog(@"testForThreesAgain"); + anyThrees = [game checkBoardForThrees]; + [scoreTextField setStringValue:[NSString stringWithFormat:@"%d",[game score]]]; + [scoreTextField setNeedsDisplay:YES]; + [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d",[game bonusMultiplier]]]; + [bonusTextField setNeedsDisplay:YES]; + if ([game score] > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS]; + if (anyThrees) + [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems + else + [self waitForFirstClick]; +} + //// allow gems to fall + //// test for threes + //// until there are no threes + +- (void)unSwap +{ + //NSLog(@"unSwap"); + + if (!muted) [[NSSound soundNamed:@"no"] play]; + + // swap positions + if (chx1 < chx2) // swapping horizontally + { + [[game gemAt:chx1:chy1] setVelocity:4:0:12]; + [[game gemAt:chx2:chy2] setVelocity:-4:0:12]; + } + else // swapping vertically + { + [[game gemAt:chx1:chy1] setVelocity:0:4:12]; + [[game gemAt:chx2:chy2] setVelocity:0:-4:12]; + } + [game swap:chx1:chy1 and:chx2:chy2]; + gameState = GAMESTATE_SWAPPING; + [self startAnimation:@selector(waitForFirstClick)]; +} + + +- (int) gameState +{ + return gameState; +} + +- (BOOL) gameIsPaused +{ + return paused; +} + +- (BOOL) useCustomBackgrounds +{ + return useCustomBackgrounds; +} + +- (NSPoint) crossHair1Position +{ + return NSMakePoint(chx1*48,chy1*48); +} + +- (NSPoint) crossHair2Position +{ + return NSMakePoint(chx2*48,chy2*48); +} + +@end diff --git a/src/GameView.h b/src/GameView.h new file mode 100644 index 0000000..2cf97b4 --- /dev/null +++ b/src/GameView.h @@ -0,0 +1,102 @@ +/* ----====----====----====----====----====----====----====----====----====---- +GameView.h (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import +#import + +@class Game, GameController, OpenGLSprite; + +@interface GameView : NSOpenGLView +{ + IBOutlet GameController *gameController; + + BOOL m_glContextInitialized; + + NSColor *backgroundColor; + NSMutableArray *gemImageArray; + NSImage *backgroundImage; + NSImage *crosshairImage; + NSImage *movehintImage; + + //OpenGLSprites! + OpenGLSprite *backgroundSprite, *crosshairSprite, *movehintSprite; + NSMutableArray *gemSpriteArray; + + //backgrounds + NSMutableArray *backgroundImagePathArray; + + id legend; + NSAttributedString *hiScoreLegend; + + NSImage *legendImage; + OpenGLSprite *legendSprite; + + NSArray *hiScoreNumbers, *hiScoreNames; + int ticsSinceLastMove, scoreScroll; + + NSPoint dragStartPoint; + + Game *game; + + NSDictionary *docTypeDictionary; + + BOOL animating, showHighScores, paused, muted, animationStatus, showHint; +} + +- (void) graphicSetUp; +- (void) loadImageArray; + +// ANIMATE +- (void) setMuted:(BOOL)value; +- (void) setShowHint:(BOOL)value; +- (void) setPaused:(BOOL)value; +- (void) setAnimating:(BOOL)value; +- (BOOL) isAnimating; +- (void) animate; + +- (void) setGame:(Game *) agame; +- (Game *) game; +- (NSArray *) imageArray; +- (NSArray *) spriteArray; +- (void) newBackground; +- (void) setLegend:(id)value; +- (void) setHTMLLegend:(NSString *)value; +- (void) setHiScoreLegend:(NSAttributedString *)value; +- (void) setHTMLHiScoreLegend:(NSString *)value; +- (void) setLastMoveDate; + +- (void) showHighScores:(NSArray *)scores andNames:(NSArray *)names; + +// Standard view create/free methods +- (id)initWithFrame:(NSRect)frame; +- (void)dealloc; + +// Drawing +- (void)drawRect:(NSRect)rect; +- (void) showScores; +- (BOOL)isOpaque; + +// Event handling +- (void)mouseDown:(NSEvent *)event; +- (void)mouseDragged:(NSEvent *)event; +- (void)mouseUp:(NSEvent *)event; + +@end diff --git a/src/GameView.m b/src/GameView.m new file mode 100644 index 0000000..d74cd37 --- /dev/null +++ b/src/GameView.m @@ -0,0 +1,677 @@ +/* ----====----====----====----====----====----====----====----====----====---- +GameView.m (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#include +//#import +//#import + +#import "GameView.h" +#import "GameController.h" +#import "Game.h" +#import "Gem.h" +// +// MW... +// +#import "ScoreBubble.h" +// +// OpenGLSprites +// +#import "OpenGLSprite.h" + + +@implementation GameView + +- (id)initWithFrame:(NSRect)frame { + + //NSData *tiffData; + + NSOpenGLPixelFormatAttribute attrs[] = { + NSOpenGLPFADepthSize, 1, + NSOpenGLPFAAccelerated, + 0}; + NSOpenGLPixelFormat *pixFmt; + + pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + self = [super initWithFrame:frame pixelFormat:pixFmt]; + + m_glContextInitialized = NO; + + animating = NO; + showHighScores = NO; + showHint = YES; + ticsSinceLastMove = 0; + + docTypeDictionary = [NSDictionary dictionary]; + + return self; +} + +- (void) dealloc +{ + if (backgroundColor) + [backgroundColor release]; + if (gemImageArray) + [gemImageArray release]; + if (gemSpriteArray) + [gemImageArray release]; + if (backgroundImagePathArray) + [backgroundImagePathArray release]; + [super dealloc]; +} + +- (void) graphicSetUp +{ + int i; + NSData *tiffData; + + backgroundColor = [[NSColor purpleColor] retain]; + + [self loadImageArray]; + + tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:@"backgroundTiffData"]; + if (tiffData) + backgroundImage = [[NSImage alloc] initWithData:tiffData]; + else + backgroundImage = [NSImage imageNamed:@"background"]; + + crosshairImage = [NSImage imageNamed:@"cross"]; + movehintImage = [NSImage imageNamed:@"movehint"]; + + ////// + // + // Make the Open GL Sprites! + // + backgroundSprite = [[OpenGLSprite alloc] initWithImage:backgroundImage + cropRectangle:NSMakeRect(0.0, 0.0, [backgroundImage size].width, [backgroundImage size].height) + size:NSMakeSize(384.0,384.0)]; + + crosshairSprite = [[OpenGLSprite alloc] initWithImage:crosshairImage + cropRectangle:NSMakeRect(0.0, 0.0, [crosshairImage size].width, [crosshairImage size].height) + size:NSMakeSize(48.0,48.0)]; + movehintSprite = [[OpenGLSprite alloc] initWithImage:movehintImage + cropRectangle:NSMakeRect(0.0, 0.0, [movehintImage size].width, [movehintImage size].height) + size:NSMakeSize(48.0,48.0)]; + if (gemSpriteArray) + [gemSpriteArray release]; + gemSpriteArray = [[NSMutableArray arrayWithCapacity:0] retain]; + for (i = 0; i < 7; i++) + { + NSImage *image = [gemImageArray objectAtIndex:i]; + OpenGLSprite *sprite = [[OpenGLSprite alloc] initWithImage:image + cropRectangle:NSMakeRect(0.0, 0.0, [image size].width, [image size].height) + size:NSMakeSize(48.0,48.0)]; + + [gemSpriteArray addObject:sprite]; + [sprite release]; + } + + if (!legendImage) + { + legendImage = [[NSImage alloc] initWithSize:NSMakeSize(384,384)]; + [legendImage lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(NSMakeRect(0,0,384,384)); + [legendImage unlockFocus]; + legendSprite = [[OpenGLSprite alloc] initWithImage:legendImage + cropRectangle:NSMakeRect(0.0, 0.0, [legendImage size].width, [legendImage size].height) + size:[legendImage size]]; + + [self setLegend:[NSImage imageNamed:@"title"]]; + } + // + // + ////// + + // if custom backgrounds are to be used initialise the array of paths to images + // + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"]) + { + NSString *customBackgroundFolderPath = [[[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"] stringByResolvingSymlinksInPath]; + + //NSLog(@"customBackgroundFolderPath = ",customBackgroundFolderPath); + + if (customBackgroundFolderPath) + { + // borrowed code here + NSDirectoryEnumerator *picturesFolderEnum; + NSString *relativeFilePath,*fullPath; + // grab all picture formats NSImage knows about - we'll assume that if we can read them, + // we can set them to be the desktop picture + NSArray *imageFormats=[NSImage imageFileTypes]; + + if (backgroundImagePathArray) + [backgroundImagePathArray autorelease]; + backgroundImagePathArray = [[NSMutableArray arrayWithCapacity:0] retain]; + // build the array + + // borrowed code here + // now we need to go scan the folder chosen, enumerating through to find all picture files + picturesFolderEnum=[[NSFileManager defaultManager] enumeratorAtPath:customBackgroundFolderPath]; + + relativeFilePath=[picturesFolderEnum nextObject]; + while (relativeFilePath) + { + fullPath=[NSString stringWithFormat:@"%@/%@",customBackgroundFolderPath,relativeFilePath]; + + // If the file's extension or type matches a format that NSImage understands, + // then we're good to go, and we add a new menu item, using the display name + // (which may have a hidden extension) for the menu item's title and passing + // the full path to the picture to store with the menu item + if ([imageFormats containsObject:[relativeFilePath pathExtension]] || + [imageFormats containsObject:NSHFSTypeOfFile(fullPath)]) + { + [backgroundImagePathArray addObject:fullPath]; + } + relativeFilePath=[picturesFolderEnum nextObject]; + } + + //NSLog(@"[backgroundImagePathArray count]= %d",[backgroundImagePathArray count]); + + // + } + + } + + [self newBackground]; + + +} + +- (void) loadImageArray +{ + BOOL useAlternateGraphics, useImportedGraphics; + useAlternateGraphics = [[NSUserDefaults standardUserDefaults] + boolForKey:@"useAlternateGraphics"]; + useImportedGraphics = [[NSUserDefaults standardUserDefaults] + boolForKey:@"useImportedGraphics"]; + if (gemImageArray) + [gemImageArray release]; + gemImageArray = [[NSMutableArray arrayWithCapacity:0] retain]; + if (!useAlternateGraphics) + { + //NSLog(@"Loading regular graphics"); + [gemImageArray addObject:[NSImage imageNamed:@"1gem"]]; + [gemImageArray addObject:[NSImage imageNamed:@"2gem"]]; + [gemImageArray addObject:[NSImage imageNamed:@"3gem"]]; + [gemImageArray addObject:[NSImage imageNamed:@"4gem"]]; + [gemImageArray addObject:[NSImage imageNamed:@"5gem"]]; + [gemImageArray addObject:[NSImage imageNamed:@"6gem"]]; + [gemImageArray addObject:[NSImage imageNamed:@"7gem"]]; + } + else + { + //NSData *tiffData = [[[NSUserDefaults standardUserDefaults] + // dataForKey:@"tiffData"] retain]; + if (!useImportedGraphics) + { + //NSLog(@"Loading alternate graphics"); + [gemImageArray addObject:[NSImage imageNamed:@"1gemA"]]; + [gemImageArray addObject:[NSImage imageNamed:@"2gemA"]]; + [gemImageArray addObject:[NSImage imageNamed:@"3gemA"]]; + [gemImageArray addObject:[NSImage imageNamed:@"4gemA"]]; + [gemImageArray addObject:[NSImage imageNamed:@"5gemA"]]; + [gemImageArray addObject:[NSImage imageNamed:@"6gemA"]]; + [gemImageArray addObject:[NSImage imageNamed:@"7gemA"]]; + } + else + { + int i = 0; + //NSLog(@"Loading custom graphics"); + for (i = 0; i < 7; i++) + { + NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i]; + NSData *tiffData = [[NSUserDefaults standardUserDefaults] + dataForKey:key]; + NSImage *gemImage = [[NSImage alloc] initWithData:tiffData]; + [gemImageArray addObject:gemImage]; + [gemImage release]; + } + + } + } +} + +- (void) setMuted:(BOOL)value +{ + muted = value; +} + +- (void) setShowHint:(BOOL)value +{ + showHint = value; +} + +- (void) setPaused:(BOOL)value +{ + paused = value; + if (paused) + { + animationStatus = animating; + animating = NO; + } + else + animating = animationStatus; +} + +- (void) setAnimating:(BOOL)value +{ + animating = value; +} + +- (BOOL) isAnimating +{ + return animating; +} + +// ANIMATE called by the Timer +- (void) animate +{ + if (!paused) + { + // + // MIKE WESSLER'S Scorebubbles + // + int b; + // + // needsUpdate added so setNeedsDisplay gets called once at most + // + BOOL needsUpdate = FALSE; + // + // animate bubbles, if any + for (b=0; b<[[game scoreBubbles] count]; b++) { + ScoreBubble *sb= [[game scoreBubbles] objectAtIndex:b]; + int more= [sb animate]; + needsUpdate = TRUE; + if (!more) { + [[game scoreBubbles] removeObjectAtIndex:b]; + b--; + } + } + // + //// + + if (animating) + { + //NSLog(@"GameView.animate"); + if (game) + { + int i,j,c; // animate each gem in the grid + c = 0; // animation accumulator + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + if ([game gemAt:i:j]) c += [[game gemAt:i:j] animate]; + if (c == 0) + [gameController animationEnded]; + } + needsUpdate = TRUE; + } + else + { + ticsSinceLastMove++; + if (ticsSinceLastMove > 500) + { + needsUpdate = TRUE; + } + } + if (needsUpdate) + [self setNeedsDisplay:YES]; + } +} + +- (void) setGame:(Game *) agame +{ + game = agame; +} +- (Game *) game +{ + return game; +} +- (NSArray *) imageArray +{ + return gemImageArray; +} +- (NSArray *) spriteArray +{ + return gemSpriteArray; +} + +- (void) newBackground +{ + if (([gameController useCustomBackgrounds])&&(backgroundImagePathArray)&&([backgroundImagePathArray count] > 0)) + { + NSString *imagePath = [backgroundImagePathArray objectAtIndex:0]; + [backgroundImagePathArray addObject:imagePath]; + [backgroundImagePathArray removeObjectAtIndex:0]; + //NSLog(@"Taking image from path: %@",imagePath); + + backgroundImage = [[NSImage alloc] initWithContentsOfFile:imagePath]; + + //NSLog(@"Image size is %f x %f",[backgroundImage size].width, [backgroundImage size].height); + + [backgroundSprite substituteTextureFromImage:backgroundImage]; + //backgroundSprite = [[OpenGLSprite alloc] initWithImage:backgroundImage + // cropRectangle:NSMakeRect(0.0, 0.0, [backgroundImage size].width, [backgroundImage size].height) + // size:NSMakeSize(384.0,384.0)]; + } + else + { + NSData *tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:@"backgroundTiffData"]; + if (tiffData) + backgroundImage = [[NSImage alloc] initWithData:tiffData]; + else + backgroundImage = [NSImage imageNamed:@"background"]; + backgroundSprite = [[OpenGLSprite alloc] initWithImage:backgroundImage + cropRectangle:NSMakeRect(0.0, 0.0, [backgroundImage size].width, [backgroundImage size].height) + size:NSMakeSize(384.0,384.0)]; + } +} + +- (void) setLegend:(id)value +{ + // NEED TO DRAW LEGEND INTO LEGENDIMAGE THEN REPLACE THE TEXTURE IN LEGENDSPRITE + + if (!value) // is null + { + //NSLog(@"Legend cleared"); + legend = value; + [self setNeedsDisplay:YES]; + return; + } + + // + // + [legendImage lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(NSMakeRect(0,0,384,384)); + if ([value isKindOfClass:[NSAttributedString class]]) + { + NSPoint legendPoint = NSMakePoint((384 - [value size].width)/2,(384 - [value size].height)/2); + [(NSAttributedString *)value drawAtPoint:legendPoint]; + } + if ([value isKindOfClass:[NSImage class]]) + { + NSPoint legendPoint = NSMakePoint((384 - [value size].width)/2,(384 - [value size].height)/2); + [(NSImage *)value compositeToPoint:legendPoint operation:NSCompositeSourceOver]; + } + [legendImage unlockFocus]; + [legendSprite replaceTextureFromImage:legendImage + cropRectangle:NSMakeRect(0.0, 0.0, [legendImage size].width, [legendImage size].height)]; + + legend = legendSprite; + ticsSinceLastMove = 0; + showHighScores = NO; + animating = NO; + + [self setNeedsDisplay:YES]; + + // + // +} + +- (void) setHTMLLegend:(NSString *)value +{ + NSData *htmlData = [NSData dataWithBytes:[value cString] length:[value length]]; + [self setLegend:[[NSAttributedString alloc] initWithHTML:htmlData documentAttributes:NULL]]; +} + +- (void) setHiScoreLegend:(NSAttributedString *)value +{ + hiScoreLegend = value; +} + +- (void) setHTMLHiScoreLegend:(NSString *)value +{ + NSData *htmlData = [NSData dataWithBytes:[value cString] length:[value length]]; + [self setHiScoreLegend:[[NSAttributedString alloc] initWithHTML:htmlData documentAttributes:NULL]]; +} + +- (void) setLastMoveDate +{ + ticsSinceLastMove = 0; +} + +- (void) showHighScores:(NSArray *)scores andNames:(NSArray *)names +{ + hiScoreNumbers = scores; + hiScoreNames = names; + showHighScores = YES; + animating = NO; + scoreScroll = 0; + [self setNeedsDisplay:YES]; +} + + +// drawRect: should be overridden in subclassers of NSView to do necessary +// drawing in order to recreate the the look of the view. It will be called +// to draw the whole view or parts of it (pay attention the rect argument); +// it will also be called during printing if your app is set up to print. + +- (void)drawRect:(NSRect)rect { + int i,j; + + // Open GL + float size = 384.0/2.0; // screenSize/2; + float clearDepth = 1.0; + + // try to fix image loading problem + if (!legendImage) + [self graphicSetUp]; + + ////////// + + if (!m_glContextInitialized) + { + glShadeModel(GL_FLAT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); // reset matrix + + glFrustum(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); // set projection matrix + glMatrixMode(GL_MODELVIEW); + + //glEnable(GL_DEPTH_TEST); // depth buffer + + glEnable(GL_BLEND); // alpha blending + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha blending + m_glContextInitialized = YES; + } + + glClearColor(0.3, 0.3, 0.3, 0.0); + glClearDepth(clearDepth); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glLoadIdentity(); // allows me to resize the window but keep position OK + + glTranslatef(-1.0,-1.0,0.0); + glScalef(1/size,1/size,1.0);// scale to screen size and width + + if (backgroundSprite) + { + [backgroundSprite blitToX:0.0 + Y:0.0 + Z:0.0]; + } + if ((game)&&(!paused)) + { + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + [[game gemAt:i :j] drawSprite]; + // + // MW - Scorebubbles + // + for (i=0; i<[[game scoreBubbles] count]; i++) { + ScoreBubble *sb= [[game scoreBubbles] objectAtIndex:i]; + [sb drawSprite]; + } + // + //// + } + + if ([gameController gameState] == GAMESTATE_AWAITINGSECONDCLICK) + { + [crosshairSprite blitToX:[gameController crossHair1Position].x + Y:[gameController crossHair1Position].y + Z:-0.5]; + } + if (showHighScores) + { + [self showScores]; // draws the HighScores in the current focused view (Quartz) + //return; // now legendSprite contains the drawing... + } + if (!legend) + { + if ((ticsSinceLastMove > 500)&&(showHint)) + { + [movehintSprite blitToX:[game hintPoint].x + Y:[game hintPoint].y + Z:-0.4 + Alpha:(sin((ticsSinceLastMove-497.0)/4.0)+1.0)/2.0]; + } + } + else + { + if (ticsSinceLastMove > 500) + [self setLegend:[NSImage imageNamed:@"title"]]; // show Logo + if ([legend isKindOfClass:[OpenGLSprite class]]) + { + //NSLog(@"Blitting legend"); + [legend blitToX:0.0 Y:0.0 Z:-0.75]; + } + } + glFlush(); + +} + +- (void) showScores +{ + int i; + NSPoint legendPoint; + NSRect panelRect; + NSMutableDictionary *attr = [NSMutableDictionary dictionaryWithCapacity:0]; + + [attr setObject:[NSColor yellowColor] forKey:NSForegroundColorAttributeName]; + + [legendImage lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(NSMakeRect(0,0,384,384)); + + [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.5] set]; + panelRect = NSMakeRect(32, 16, 384-64, 384-32); + NSRectFill(panelRect); + + + legendPoint = NSMakePoint((384 - [hiScoreLegend size].width)/2,384 - [hiScoreLegend size].height*1.5 + scoreScroll); + + [hiScoreLegend drawAtPoint:legendPoint]; + + for (i = 0; i< 10; i++) + { + NSString *s1 = [NSString stringWithFormat:@"%d",[[hiScoreNumbers objectAtIndex:i] intValue]]; + NSString *s2 = [hiScoreNames objectAtIndex:i]; + NSPoint q1 = NSMakePoint( 192+20+1, 384 - 84 - i*30 + scoreScroll - 1); + NSPoint q2 = NSMakePoint( 192-20-[s2 sizeWithAttributes:attr].width+1, 384 - 84 - i*30 + scoreScroll - 1); + NSPoint p1 = NSMakePoint( 192+20, 384 - 84 - i*30 + scoreScroll); + NSPoint p2 = NSMakePoint( 192-20-[s2 sizeWithAttributes:attr].width, 384 - 84 - i*30 + scoreScroll); + + [attr setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName]; + + [s1 drawAtPoint:q1 withAttributes:attr]; + [s2 drawAtPoint:q2 withAttributes:attr]; + + [attr setObject:[NSColor yellowColor] forKey:NSForegroundColorAttributeName]; + + [s1 drawAtPoint:p1 withAttributes:attr]; + [s2 drawAtPoint:p2 withAttributes:attr]; + } + [legendImage unlockFocus]; + [legendSprite replaceTextureFromImage:legendImage + cropRectangle:NSMakeRect(0.0, 0.0, [legendImage size].width, [legendImage size].height)]; + + legend = legendSprite; + + showHighScores = NO; +} + +// Views which totally redraw their whole bounds without needing any of the +// views behind it should override isOpaque to return YES. This is a performance +// optimization hint for the display subsystem. This applies to DotView, whose +// drawRect: does fill the whole rect its given with a solid, opaque color. + +- (BOOL)isOpaque { + return YES; +} + +// Recommended way to handle events is to override NSResponder (superclass +// of NSView) methods in the NSView subclass. One such method is mouseUp:. +// These methods get the event as the argument. The event has the mouse +// location in window coordinates; use convertPoint:fromView: (with "nil" +// as the view argument) to convert this point to local view coordinates. +// +// Note that once we get the new center, we call setNeedsDisplay:YES to +// mark that the view needs to be redisplayed (which is done automatically +// by the AppKit). + +// +// I want to add a new behaviour here, the click-drag for a square +// I'm prolly going to have to fake this by sending gameController two clicks +// I might have to change the shape of the mouse cursor too! +// +- (void)mouseDown:(NSEvent *)event { + NSPoint eventLocation = [event locationInWindow]; + NSPoint center = [self convertPoint:eventLocation fromView:nil]; + dragStartPoint = center; +} + +- (void)mouseDragged:(NSEvent *)event { + // do nothing for now +} + +- (void)mouseUp:(NSEvent *)event { + NSPoint eventLocation = [event locationInWindow]; + NSPoint center = [self convertPoint:eventLocation fromView:nil]; + + // check situation - is this a first or second mouseUp + if ([gameController gameState] == GAMESTATE_AWAITINGSECONDCLICK) + { + //NSLog(@"click at :%f,%f",center.x,center.y); + [gameController receiveClickAt:center.x:center.y]; + } + else if ([gameController gameState] == GAMESTATE_AWAITINGFIRSTCLICK) + { + int chx1 = floor(dragStartPoint.x / 48); + int chy1 = floor(dragStartPoint.y / 48); + int chx2 = floor(center.x / 48); + int chy2 = floor(center.y / 48); + if ((chx2 != chx1)^(chy2 != chy1)) // xor checks if a valid shove's occurred! + { + [gameController receiveClickAt:dragStartPoint.x:dragStartPoint.y]; + [gameController receiveClickAt:center.x:center.y]; + } + else + { + [gameController receiveClickAt:center.x:center.y]; + } + } + +} + + +@end diff --git a/src/Gem.h b/src/Gem.h new file mode 100644 index 0000000..30ba974 --- /dev/null +++ b/src/Gem.h @@ -0,0 +1,112 @@ +/* ----====----====----====----====----====----====----====----====----====---- +Gem.h (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import +#import + +#define GEMSTATE_RESTING 1 +#define GEMSTATE_FADING 2 +#define GEMSTATE_FALLING 3 +#define GEMSTATE_SHAKING 4 +#define GEMSTATE_ERUPTING 5 +#define GEMSTATE_MOVING 6 +// +// MW... +// +#define GEMSTATE_SHIVERING 7 +// + +#define FADE_STEPS 8.0 +#define GRAVITY 1.46 +#define GEM_ERUPT_DELAY 45 + +// +// Open GL Z value for gems +// +#define GEM_SPRITE_Z -0.25 +// + +@class OpenGLSprite; + +@interface Gem : NSObject +{ + int gemType; + NSImage *image; + + // Open GL + OpenGLSprite *sprite; + // + + NSSound *tink; + NSSound *sploink; + + // MW + int waitForFall; + // + + int state; + int animationCounter; + double vx, vy; + NSPoint positionOnScreen, positionOnBoard; +} + +- (id) init; +- (void) dealloc; + ++ (Gem *) gemWithNumber:(int) d andImage:(NSImage *)img; ++ (Gem *) gemWithNumber:(int) d andSprite:(OpenGLSprite *)aSprite; + +- (int) animate; +- (void) fade; +- (void) fall; +- (void) shake; +- (void) erupt; +// MW... +- (void) shiver; +// + +- (int) gemType; +- (void) setGemType:(int) d; + +- (NSImage *) image; +- (void) setImage:(NSImage *) value; +- (void) drawImage; + +- (OpenGLSprite *) sprite; +- (void) setSprite:(OpenGLSprite *) value; +- (void) drawSprite; + +- (int) state; +- (void) setState:(int) value; + +- (int) animationCounter; +- (void) setAnimationCounter:(int) value; + +- (NSPoint) positionOnScreen; +- (void) setPositionOnScreen:(int) valx :(int) valy; +- (void) setVelocity:(int) valx :(int) valy :(int) steps; + +- (NSPoint) positionOnBoard; +- (void) setPositionOnBoard:(int) valx :(int) valy; + +- (void) setSoundsTink:(NSSound *) tinkSound Sploink:(NSSound *) sploinkSound; + +@end diff --git a/src/Gem.m b/src/Gem.m new file mode 100644 index 0000000..7497294 --- /dev/null +++ b/src/Gem.m @@ -0,0 +1,278 @@ +/* ----====----====----====----====----====----====----====----====----====---- +Gem.m (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + + +#import "Gem.h" + +// Open GL +#import "OpenGLSprite.h" +// + +@implementation Gem + +- (id) init +{ + self = [super init]; + [self setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]]; + // MW... + waitForFall= 0; + // + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + ++ (Gem *) gemWithNumber:(int) d andImage:(NSImage *)img +{ + Gem *result = [[[Gem alloc] init] autorelease]; + [result setGemType:d]; + [result setImage:img]; + [result setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]]; + return result; +} + ++ (Gem *) gemWithNumber:(int) d andSprite:(OpenGLSprite *)aSprite +{ + Gem *result = [[[Gem alloc] init] autorelease]; + [result setGemType:d]; + [result setSprite:aSprite]; + [result setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]]; + return result; +} + +- (int) animate +{ + if (state == GEMSTATE_RESTING) + { + [self setPositionOnScreen:positionOnBoard.x*48:positionOnBoard.y*48]; + animationCounter = 0; + } + if (state == GEMSTATE_FADING) + { + [self setPositionOnScreen:positionOnBoard.x*48:positionOnBoard.y*48]; + if (animationCounter > 0) animationCounter--; + } + // MW... + if (state== GEMSTATE_SHIVERING) { + positionOnScreen.x= positionOnBoard.x*48+(rand()%3)-1; + positionOnScreen.y= positionOnBoard.y*48; + } + // + if (state == GEMSTATE_FALLING) + { + if (animationCounter (positionOnBoard.y*48)) + { + positionOnScreen.y += vy; + positionOnScreen.x = positionOnBoard.x*48; + vy -= GRAVITY; + animationCounter++; + } + else + { + [tink play]; + positionOnScreen.y = positionOnBoard.y * 48; + state = GEMSTATE_RESTING; + } + } + if (state == GEMSTATE_SHAKING) + { + positionOnScreen.x = positionOnBoard.x*48+(rand()%5)-2; + positionOnScreen.y = positionOnBoard.y*48+(rand()%5)-2; + if (animationCounter > 1) animationCounter--; + else state = GEMSTATE_RESTING; + } + if (state == GEMSTATE_ERUPTING) + { + if (positionOnScreen.y > -48) + { + if (animationCounter < GEM_ERUPT_DELAY) + { + positionOnScreen.x = positionOnBoard.x*48+(rand()%5)-2; + positionOnScreen.y = positionOnBoard.y*48+(rand()%5)-2; + } + else + { + positionOnScreen.y += vy; + positionOnScreen.x += vx; + vy -= GRAVITY; + } + animationCounter++; + } + else + { + animationCounter = 0; + } + } + if (state == GEMSTATE_MOVING) + { + if (animationCounter > 0) + { + positionOnScreen.y += vy; + positionOnScreen.x += vx; + animationCounter--; + } + else state = GEMSTATE_RESTING; + } + return animationCounter; +} + +- (void) fade +{ + [sploink play]; + state = GEMSTATE_FADING; + animationCounter = FADE_STEPS; +} +- (void) fall +{ + state = GEMSTATE_FALLING; + // MW... + waitForFall= rand()%6; + // + vx = 0; + vy = 0; + animationCounter = 1; +} +// MW... +- (void) shiver +{ + state= GEMSTATE_SHIVERING; + animationCounter= 0; +} +// +- (void) shake +{ + state = GEMSTATE_SHAKING; + animationCounter = 25; +} +- (void) erupt +{ + [self setVelocity:(rand()%5)-2:(rand()%7)-2:1]; + state = GEMSTATE_ERUPTING; + animationCounter = GEM_ERUPT_DELAY; +} + +- (int) gemType +{ + return gemType; +} +- (void) setGemType:(int) d +{ + gemType = d; +} + +- (NSImage *) image +{ + return image; +} +- (void) setImage:(NSImage *) value +{ + image = value; +} +- (void) drawImage +{ + if (state == GEMSTATE_FADING) + [[self image] compositeToPoint:[self positionOnScreen] operation:NSCompositeSourceOver fraction:(animationCounter / FADE_STEPS)]; + else + [[self image] compositeToPoint:[self positionOnScreen] operation:NSCompositeSourceOver]; +} + +- (OpenGLSprite *) sprite +{ + return sprite; +} +- (void) setSprite:(OpenGLSprite *) value +{ + sprite = value; +} +- (void) drawSprite +{ + if (state == GEMSTATE_FADING) + [[self sprite] blitToX:positionOnScreen.x + Y:positionOnScreen.y + Z:GEM_SPRITE_Z + Alpha:(animationCounter / FADE_STEPS)]; + else + [[self sprite] blitToX:positionOnScreen.x + Y:positionOnScreen.y + Z:GEM_SPRITE_Z + Alpha:1.0]; +} + +- (int) state +{ + return state; +} +- (void) setState:(int) value +{ + state = value; +} + +- (int) animationCounter +{ + return animationCounter; +} +- (void) setAnimationCounter:(int) value +{ + animationCounter = value; +} + +- (NSPoint) positionOnScreen +{ + return positionOnScreen; +} +- (void) setPositionOnScreen:(int) valx :(int) valy +{ + positionOnScreen.x = valx; + positionOnScreen.y = valy; +} +- (void) setVelocity:(int) valx :(int) valy :(int) steps +{ + vx = valx; + vy = valy; + animationCounter = steps; + state = GEMSTATE_MOVING; +} + +- (NSPoint) positionOnBoard +{ + return positionOnBoard; +} +- (void) setPositionOnBoard:(int) valx :(int) valy +{ + positionOnBoard.x = valx; + positionOnBoard.y = valy; +} + +- (void) setSoundsTink:(NSSound *) tinkSound Sploink:(NSSound *) sploinkSound +{ + tink = tinkSound; + sploink = sploinkSound; +} + +@end diff --git a/src/MyTimerView.h b/src/MyTimerView.h new file mode 100644 index 0000000..a4cd32e --- /dev/null +++ b/src/MyTimerView.h @@ -0,0 +1,62 @@ +/* ----====----====----====----====----====----====----====----====----====---- +MyTimerView.h (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import + +@interface MyTimerView : NSView +{ + float meter; + float decrement; + id target; + SEL runOutSelector; + SEL runOverSelector; + NSTimer *timer; + BOOL isRunning; + + NSColor *color1; + NSColor *color2; + NSColor *colorOK; + NSColor *backColor; +} +// Standard view create/free methods +- (id)initWithFrame:(NSRect)frame; +- (void)dealloc; + +// Drawing +- (void)drawRect:(NSRect)rect; +- (BOOL)isOpaque; + +// Utility +- (void) setPaused:(BOOL) value; +- (void) incrementMeter:(float) value; +- (void) setDecrement:(float) value; +- (void) decrementMeter:(float) value; +- (void) setTimerRunningEvery:(NSTimeInterval) timeInterval + decrement:(float) value + withTarget:(id) targ + whenRunOut:(SEL) runOutSel + whenRunOver:(SEL) runOverSel; +- (void) runTimer; +- (void) setTimer:(float)value; +- (float) meter; + + +@end diff --git a/src/MyTimerView.m b/src/MyTimerView.m new file mode 100644 index 0000000..15fce49 --- /dev/null +++ b/src/MyTimerView.m @@ -0,0 +1,165 @@ +/* ----====----====----====----====----====----====----====----====----====---- +MyTimerView.m (jeweltoy) + +JewelToy is a simple game played against the clock. +Copyright (C) 2001 Giles Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import "MyTimerView.h" + +@implementation MyTimerView + +- (id)initWithFrame:(NSRect)frame { + [super initWithFrame:frame]; + + meter = 0.5; + color1 = [[NSColor redColor] retain]; + color2 = [[NSColor yellowColor] retain]; + colorOK = [[NSColor greenColor] retain]; + backColor = [[NSColor blackColor] retain]; + isRunning = NO; + + return self; +} + +// dealloc is the method called when objects are being freed. (Note that "release" +// is called to release objects; when the number of release calls reduce the +// total reference count on an object to zero, dealloc is called to free +// the object. dealloc should free any memory allocated by the subclass +// and then call super to get the superclass to do additional cleanup. + +- (void)dealloc { + [color1 release]; + [color2 release]; + [colorOK release]; + [backColor release]; + [super dealloc]; +} + +// drawRect: should be overridden in subclassers of NSView to do necessary +// drawing in order to recreate the the look of the view. It will be called +// to draw the whole view or parts of it (pay attention the rect argument); + +- (void)drawRect:(NSRect)rect { + NSRect dotRect; + + [backColor set]; + NSRectFill([self bounds]); // Equiv to [[NSBezierPath bezierPathWithRect:[self bounds]] fill] + + dotRect.origin.x = 4; + dotRect.origin.y = 4; + dotRect.size.width = meter * ([self bounds].size.width - 8); + dotRect.size.height = [self bounds].size.height - 8; + + [colorOK set]; + // + // another MW change... + // + if (decrement!=0) + { + if (meter < 0.3) [color2 set]; + if (meter < 0.1) [color1 set]; + } + + NSRectFill(dotRect); // Equiv to [[NSBezierPath bezierPathWithRect:dotRect] fill] +} + +- (BOOL)isOpaque { + return YES; +} + +// Utility +- (void) setPaused:(BOOL) value +{ + isRunning = !value; +} + +- (void) incrementMeter:(float) value +{ + meter += value; + if (meter > 1) meter = 1; + [self setNeedsDisplay:YES]; +} + +- (void) setDecrement:(float) value +{ + decrement = value; +} + +- (void) decrementMeter:(float) value +{ + meter -= value; + if (meter < 0) meter = 0; + [self setNeedsDisplay:YES]; +} + +- (void) setTimerRunningEvery:(NSTimeInterval) timeInterval + decrement:(float) value + withTarget:(id) targ + whenRunOut:(SEL) runOutSel + whenRunOver:(SEL) runOverSel +{ + decrement = value; + target = targ; + runOutSelector = runOutSel; + runOverSelector = runOverSel; + if (timer) + { + [timer invalidate]; + } + timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval + target:self + selector:@selector(runTimer) + userInfo:self + repeats:YES]; + isRunning = YES; +} + +- (void) runTimer +{ + if (isRunning) + { + if (meter == 1) + { + isRunning = NO; + [target performSelector:runOverSelector]; + return; + } + [self decrementMeter:decrement]; + if (meter == 0 && decrement!=0) // MW change added '&& decrement' + { + isRunning = NO; + [target performSelector:runOutSelector]; + return; + } + } +} + +- (void) setTimer:(float)value +{ + isRunning = NO; + meter = value; + [self setNeedsDisplay:YES]; +} + +- (float) meter +{ + return meter; +} + + +@end diff --git a/src/OpenGLSprite.h b/src/OpenGLSprite.h new file mode 100644 index 0000000..865e720 --- /dev/null +++ b/src/OpenGLSprite.h @@ -0,0 +1,41 @@ +// +// OpenGLSprite.h +// GL_BotChallenge +// +// Created by Giles Williams on Fri Jun 21 2002. +// Copyright (c) 2001 __MyCompanyName__. All rights reserved. +// + +#import +#import +#import +//#import + +#define OPEN_GL_SPRITE_MIN_WIDTH 64.0 +#define OPEN_GL_SPRITE_MIN_HEIGHT 64.0 + +@interface OpenGLSprite : NSObject { + + NSData* textureData; + GLuint texName; + + NSRect textureCropRect; + NSSize textureSize; + NSSize size; +} + + + +- (id) init; +- (id) initWithImage:(NSImage *)textureImage cropRectangle:(NSRect)cropRect size:(NSSize) spriteSize; +- (void) dealloc; + +- (void)blitToX:(float)x Y:(float)y Z:(float)z; +- (void)blitToX:(float)x Y:(float)y Z:(float)z Alpha:(float)a; + +- (void)makeTextureFromImage:(NSImage *)texImage cropRectangle:(NSRect)cropRect size:(NSSize)spriteSize; + +- (void)replaceTextureFromImage:(NSImage *)texImage cropRectangle:(NSRect)cropRect; +- (void)substituteTextureFromImage:(NSImage *)texImage; + +@end diff --git a/src/OpenGLSprite.m b/src/OpenGLSprite.m new file mode 100644 index 0000000..42e2ecd --- /dev/null +++ b/src/OpenGLSprite.m @@ -0,0 +1,261 @@ +// +// OpenGLSprite.m +// GL_BotChallenge +// +// Created by Giles Williams on Fri Jun 21 2002. +// Copyright (c) 2001 __MyCompanyName__. All rights reserved. +// + +#import "OpenGLSprite.h" + + +@implementation OpenGLSprite + +- (id) init +{ + self = [super init]; + return self; +} + +- (id) initWithImage:(NSImage *)textureImage cropRectangle:(NSRect)cropRect size:(NSSize) spriteSize +{ + self = [super init]; + [self makeTextureFromImage:textureImage cropRectangle:cropRect size:spriteSize]; + return self; + +} + +- (void) dealloc +{ + const GLuint delTextures[1] = { texName }; + glDeleteTextures(1, delTextures); // clean up the texture from the 3d card's memory + if (textureData) + [textureData release]; + [super dealloc]; +} + +- (void)blitToX:(float)x Y:(float)y Z:(float)z +{ + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, texName); + glBegin(GL_QUADS); + + glTexCoord2f(0.0, 1.0-textureCropRect.size.height); + glVertex3f(x, y+size.height, z); + + glTexCoord2f(0.0, 1.0); + glVertex3f(x, y, z); + + glTexCoord2f(textureCropRect.size.width, 1.0); + glVertex3f(x+size.width, y, z); + + glTexCoord2f(textureCropRect.size.width, 1.0-textureCropRect.size.height); + glVertex3f(x+size.width, y+size.height, z); + + glEnd(); + glDisable(GL_TEXTURE_2D); +} + +- (void)blitToX:(float)x Y:(float)y Z:(float)z Alpha:(float)a +{ + if (a < 0.0) + a = 0.0; // clamp the alpha value + if (a > 1.0) + a = 1.0; // clamp the alpha value + glEnable(GL_TEXTURE_2D); + glColor4f(1.0, 1.0, 1.0, a); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, texName); + glBegin(GL_QUADS); + + glTexCoord2f(0.0, 1.0-textureCropRect.size.height); + glVertex3f(x, y+size.height, z); + + glTexCoord2f(0.0, 1.0); + glVertex3f(x, y, z); + + glTexCoord2f(textureCropRect.size.width, 1.0); + glVertex3f(x+size.width, y, z); + + glTexCoord2f(textureCropRect.size.width, 1.0-textureCropRect.size.height); + glVertex3f(x+size.width, y+size.height, z); + + glEnd(); + glDisable(GL_TEXTURE_2D); +} + +- (void)makeTextureFromImage:(NSImage *)texImage cropRectangle:(NSRect)cropRect size:(NSSize)spriteSize +{ + NSBitmapImageRep* bitmapImageRep; + NSRect textureRect = NSMakeRect(0.0,0.0,OPEN_GL_SPRITE_MIN_WIDTH,OPEN_GL_SPRITE_MIN_HEIGHT); + NSImage* image; + + if (!texImage) + return; + + size = spriteSize; + textureCropRect = cropRect; + + //NSLog(@"texImage size is %f %f - textureRect.size is %f %f", [texImage size].width, [texImage size].height, textureRect.size.width, textureRect.size.height); + + // correct size for texture to a power of two +/** + while (textureRect.size.width < [texImage size].width) + textureRect.size.width *= 2; + while (textureRect.size.height < [texImage size].height) + textureRect.size.height *= 2; +**/ + while (textureRect.size.width < cropRect.size.width) + textureRect.size.width *= 2; + while (textureRect.size.height < cropRect.size.height) + textureRect.size.height *= 2; + + textureRect.origin= NSMakePoint(0,0); + textureCropRect.origin= NSMakePoint(0,0); + + textureSize = textureRect.size; + + image = [[NSImage alloc] initWithSize:textureRect.size]; + + [image lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(textureRect); + [texImage drawInRect:textureCropRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0]; + bitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:textureRect]; + [image unlockFocus]; + + [image release]; + // normalise textureCropRect size to 0.0 -> 1.0 + textureCropRect.size.width /= textureRect.size.width; + textureCropRect.size.height /= textureRect.size.height; + + //NSLog(@"Texture has :\n%d bitsPerPixel\n%d bytesPerPlane\n%d bytesPerRow",[bitmapImageRep bitsPerPixel],[bitmapImageRep bytesPerPlane],[bitmapImageRep bytesPerRow]); + //NSLog(@"Texture is :\n%f x %f pixels, using %f x %f",textureRect.size.width,textureRect.size.height,textureCropRect.size.width,textureCropRect.size.height); + + if (textureData) + [textureData autorelease]; + textureData = [[NSData dataWithBytes:[bitmapImageRep bitmapData] length:textureRect.size.width*textureRect.size.height*4] retain]; + [bitmapImageRep release]; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glGenTextures(1, &texName); // get a new unique texture name + glBindTexture(GL_TEXTURE_2D, texName); // initialise it + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureRect.size.width, textureRect.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, [textureData bytes]); + +} + +- (void)replaceTextureFromImage:(NSImage *)texImage cropRectangle:(NSRect)cropRect +{ + NSBitmapImageRep* bitmapImageRep; + NSRect textureRect = NSMakeRect(0.0,0.0,OPEN_GL_SPRITE_MIN_WIDTH,OPEN_GL_SPRITE_MIN_HEIGHT); + NSImage* image; + + if (!texImage) + return; + + textureCropRect = cropRect; + + //NSLog(@"texImage size is %f %f - textureRect.size is %f %f", [texImage size].width, [texImage size].height, textureRect.size.width, textureRect.size.height); + + // correct size for texture to a power of two + while (textureRect.size.width < cropRect.size.width) + textureRect.size.width *= 2; + while (textureRect.size.height < cropRect.size.height) + textureRect.size.height *= 2; + + if ((textureRect.size.width != textureSize.width)||(textureRect.size.height != textureSize.height)) + { + NSLog(@"ERROR! replacement texture isn't the same size as original texture"); + NSLog(@"cropRect %f x %f textureSize %f x %f",textureRect.size.width, textureRect.size.height, textureSize.width, textureSize.height); + return; + } + + textureRect.origin= NSMakePoint(0,0); + //textureRect.size = textureSize; + textureCropRect.origin= NSMakePoint(0,0); + + image = [[NSImage alloc] initWithSize:textureRect.size]; + + [image lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(textureRect); + [texImage drawInRect:textureCropRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0]; + bitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:textureRect]; + [image unlockFocus]; + + [image release]; + // normalise textureCropRect size to 0.0 -> 1.0 + textureCropRect.size.width /= textureRect.size.width; + textureCropRect.size.height /= textureRect.size.height; + + //NSLog(@"Texture has :\n%d bitsPerPixel\n%d bytesPerPlane\n%d bytesPerRow",[bitmapImageRep bitsPerPixel],[bitmapImageRep bytesPerPlane],[bitmapImageRep bytesPerRow]); + //NSLog(@"Texture is :\n%f x %f pixels, using %f x %f",textureRect.size.width,textureRect.size.height,textureCropRect.size.width,textureCropRect.size.height); + + if (textureData) + [textureData autorelease]; + textureData = [[NSData dataWithBytes:[bitmapImageRep bitmapData] length:textureSize.width*textureSize.height*4] retain]; + [bitmapImageRep release]; + + glBindTexture(GL_TEXTURE_2D, texName); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureSize.width, textureSize.height, GL_RGBA, GL_UNSIGNED_BYTE, [textureData bytes]); + +} + +- (void)substituteTextureFromImage:(NSImage *)texImage +{ + NSBitmapImageRep* bitmapImageRep; + NSRect cropRect = NSMakeRect(0.0,0.0,[texImage size].width,[texImage size].height); + NSRect textureRect = NSMakeRect(0.0,0.0,textureSize.width,textureSize.height); + NSImage* image; + + if (!texImage) + return; + + image = [[NSImage alloc] initWithSize:textureSize]; + + [image lockFocus]; + [[NSColor clearColor] set]; + NSRectFill(textureRect); + [texImage drawInRect:textureRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0]; + bitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:textureRect]; + [image unlockFocus]; + + [image release]; + // normalise textureCropRect size to 0.0 -> 1.0 + textureCropRect = NSMakeRect(0.0,0.0,1.0,1.0); + + //NSLog(@"Texture has :\n%d bitsPerPixel\n%d bytesPerPlane\n%d bytesPerRow",[bitmapImageRep bitsPerPixel],[bitmapImageRep bytesPerPlane],[bitmapImageRep bytesPerRow]); + //NSLog(@"Texture is :\n%f x %f pixels, using %f x %f",textureRect.size.width,textureRect.size.height,textureCropRect.size.width,textureCropRect.size.height); + + if ([bitmapImageRep bitsPerPixel]==32) + { + if (textureData) + [textureData autorelease]; + textureData = [[NSData dataWithBytes:[bitmapImageRep bitmapData] length:textureSize.width*textureSize.height*4] retain]; + + glBindTexture(GL_TEXTURE_2D, texName); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureSize.width, textureSize.height, GL_RGBA, GL_UNSIGNED_BYTE, [textureData bytes]); + } + else if ([bitmapImageRep bitsPerPixel]==24) + { + if (textureData) + [textureData autorelease]; + textureData = [[NSData dataWithBytes:[bitmapImageRep bitmapData] length:textureSize.width*textureSize.height*3] retain]; + + glBindTexture(GL_TEXTURE_2D, texName); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureSize.width, textureSize.height, GL_RGB, GL_UNSIGNED_BYTE, [textureData bytes]); + } + [bitmapImageRep release]; +} + +@end diff --git a/src/ScoreBubble.h b/src/ScoreBubble.h new file mode 100644 index 0000000..d5daead --- /dev/null +++ b/src/ScoreBubble.h @@ -0,0 +1,60 @@ +// +// ScoreBubble.h +// jeweltoy +// +// Created by Mike Wessler on Sat Jun 15 2002. +// +/* +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +----====----====----====----====----====----====----====----====----====---- */ + +#import + +// Open GL Z value for scorebubbles +// +#define SCOREBUBBLE_SPRITE_Z -0.30 +// + +@class OpenGLSprite; + +@interface ScoreBubble : NSObject { + int value; + NSPoint screenLocation; + int animationCount; + NSImage *image; + + // Open GL + // + OpenGLSprite *sprite; + // +} + ++(ScoreBubble *)scoreWithValue:(int)value At:(NSPoint)loc Duration:(int)count; + +-(void)drawImage; +-(void)drawSprite; + +-(id)initWithValue:(int)value At:(NSPoint)loc Duration:(int)count; +-(int)animate; + +-(int)animationCount; +-(void)setAnimationCount:(int)count; + +-(int)value; + +-(NSImage *)image; + +-(NSPoint)screenLocation; +@end diff --git a/src/ScoreBubble.m b/src/ScoreBubble.m new file mode 100644 index 0000000..b63fea7 --- /dev/null +++ b/src/ScoreBubble.m @@ -0,0 +1,137 @@ +// +// ScoreBubble.m +// jeweltoy +// +// Created by Mike Wessler on Sat Jun 15 2002. +// +/* + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + ----====----====----====----====----====----====----====----====----====---- */ + +#import "ScoreBubble.h" + +// Open GL +// +#import "OpenGLSprite.h" +// + +NSMutableDictionary *stringAttributes; + +@implementation ScoreBubble + ++(ScoreBubble *)scoreWithValue:(int)val At:(NSPoint)loc Duration:(int)count +{ + return [[[[self class] alloc] initWithValue:val At:loc Duration:count] autorelease]; +} + +-(id)initWithValue:(int)val At:(NSPoint)loc Duration:(int)count; +{ + NSString *str= [NSString stringWithFormat:@"%d", val]; + NSSize strsize; + if (self=[super init]) { + if (!stringAttributes) { + stringAttributes= [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"ArialNarrow-Bold" size:18], + NSFontAttributeName, [NSColor blackColor], NSForegroundColorAttributeName, NULL]; + [stringAttributes retain]; + } + strsize= [str sizeWithAttributes:stringAttributes]; + strsize.width+= 3; + strsize.height+=1; + value= val; + screenLocation= loc; + screenLocation.x-=strsize.width/2; + screenLocation.y-=strsize.height/2; + animationCount= count; + image= [[NSImage alloc] initWithSize:strsize]; + [image lockFocus]; + [stringAttributes setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName]; + [str drawAtPoint:NSMakePoint(2,0) withAttributes:stringAttributes]; + [stringAttributes setObject:[NSColor yellowColor] forKey:NSForegroundColorAttributeName]; + [str drawAtPoint:NSMakePoint(1,1) withAttributes:stringAttributes]; + [image unlockFocus]; + + // Open GL + // + sprite = [[OpenGLSprite alloc] initWithImage:image + cropRectangle:NSMakeRect(0, 0, [image size].width, [image size].height) + size:[image size]]; + // + } + return self; +} + +- (void) dealloc +{ + [image release]; + [sprite release]; + + [super dealloc]; +} + +-(void)drawImage +{ + float alpha= (float)animationCount/20; + if (alpha>1) { + alpha= 1; + } + [image compositeToPoint:screenLocation operation:NSCompositeSourceOver fraction:alpha]; +} + +-(void)drawSprite +{ + float alpha= (float)animationCount/20; + if (alpha>1) { + alpha= 1; + } + [sprite blitToX:screenLocation.x + Y:screenLocation.y + Z:SCOREBUBBLE_SPRITE_Z + Alpha:alpha]; +} + +-(int)animate +{ + if (animationCount>0) { + screenLocation.y++; + animationCount--; + } + return animationCount; +} + +-(int)animationCount +{ + return animationCount; +} +-(void)setAnimationCount:(int)count +{ + animationCount= count; +} + +-(int)value +{ + return value; +} + +-(NSImage *)image +{ + return image; +} + +-(NSPoint)screenLocation +{ + return screenLocation; +} + +@end -- 2.11.4.GIT