1 /* ----====----====----====----====----====----====----====----====----====----
2 GameController.m (jeweltoy)
4 JewelToy is a simple game played against the clock.
5 Copyright (C) 2001 Giles Williams
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 ----====----====----====----====----====----====----====----====----====---- */
22 #import "GameController.h"
28 @implementation GameController
30 @synthesize gameState = _gameState;
32 @dynamic crossHair1Position;
33 @dynamic crossHair2Position;
35 @synthesize paused = _paused;
41 hiScores = [[NSUserDefaults standardUserDefaults] arrayForKey:@"hiScores"];
43 //NSLog(@"hiScores : %@",hiScores);
45 if ((!hiScores)||([hiScores count] < 8))
47 //NSLog(@"Creating High Score Tables");
48 hiScores = [self makeBlankHiScoresWith:hiScores];
49 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
53 noMoreMovesString = [[NSBundle mainBundle]
54 localizedStringForKey:@"NoMoreMovesHTML"
56 jeweltoyStartString = [[NSBundle mainBundle]
57 localizedStringForKey:@"JewelToyStartHTML"
59 gameOverString = [[NSBundle mainBundle]
60 localizedStringForKey:@"GameOverHTML"
62 titleImage = [NSImage imageNamed:@"title"];
64 gameNames = [hiScores objectAtIndex:0];
65 gameScores = [hiScores objectAtIndex:1];
67 game = [[Game alloc] init];
68 animationTimerLock = [[NSLock alloc] init];
70 gemMoveSize = GEM_GRAPHIC_SIZE;
71 gemMoveSpeed = GEM_MOVE_SPEED;
72 gemMoveSteps = gemMoveSize / gemMoveSpeed;
74 useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
75 useImportedGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useImportedGraphics"];
77 useCustomBackgrounds = [[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"];
78 customBackgroundFolderPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"];
79 if (!customBackgroundFolderPath)
80 customBackgroundFolderPath = [[NSBundle mainBundle] localizedStringForKey:@"PicturesFolderPath"
87 if (noMoreMovesString) [noMoreMovesString release];
88 if (jeweltoyStartString) [jeweltoyStartString release];
89 if (gameOverString) [gameOverString release];
90 if (game) [game release];
91 if (animationTimerLock) [animationTimerLock release];
92 if (timer) [timer release];
93 if (hiScores) [hiScores release];
99 [gameWindow setFrameAutosaveName:@"gameWindow"];
100 //useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
103 - (void)windowWillClose:(NSNotification *)aNotification
105 id obj = [aNotification object];
106 if (obj == aboutPanel)
108 //NSLog(@"Someone closed the 'About' window");
112 if (obj == prefsPanel)
114 //NSLog(@"Someone closed the 'Preferences' window");
115 useAlternateGraphics = [prefsAlternateGraphicsButton state];
116 [[NSUserDefaults standardUserDefaults] setBool:useAlternateGraphics
117 forKey:@"useAlternateGraphics"];
118 [[NSUserDefaults standardUserDefaults] setBool:useImportedGraphics
119 forKey:@"useImportedGraphics"];
121 useCustomBackgrounds = [prefsCustomBackgroundCheckbox state];
122 [[NSUserDefaults standardUserDefaults] setBool:useCustomBackgrounds
123 forKey:@"useCustomBackgrounds"];
124 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"customBackgroundFolderPath"];
125 [[NSUserDefaults standardUserDefaults] setObject:[prefsCustomBackgroundFolderTextField stringValue]
126 forKey:@"customBackgroundFolderPath"];
129 //[gameView loadImageArray];
130 [gameView graphicSetUp];
131 [gameView newBackground];
132 if (game) [game setSpritesFrom:gameView.gemSpriteArray];
133 [gameView setNeedsDisplay:YES];
138 if (obj == gameWindow)
140 //NSLog(@"Someone closed the window - shutting down JewelToy");
141 [NSApp terminate:self];
146 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
147 #pragma unused (returnCode, contextInfo)
148 [prefsCustomBackgroundFolderTextField setStringValue:[[sheet filenames] objectAtIndex:0]];
151 // TODO: move algorithm to its own method
152 - (IBAction)prefsGraphicDropAction
155 // slice and dice importedImage, saving images to defaults
157 NSImage *importedImage = [prefsAlternateGraphicsImageView image];
161 NSRect cropRect = NSMakeRect(0.0,0.0,[importedImage size].width/7.0,[importedImage size].height);
162 NSRect gemRect = NSMakeRect(0.0,0.0,48.0,48.0);
163 NSSize imageSize = NSMakeSize(48.0,48.0);
164 for (i = 0; i < 7; i++)
166 NSImage *gemImage = [[NSImage alloc] initWithSize:imageSize];
167 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
168 cropRect.origin.x = i * [importedImage size].width/7.0;
169 [gemImage lockFocus];
170 [[NSColor clearColor] set];
172 [importedImage drawInRect:gemRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0];
173 [gemImage unlockFocus];
174 [[NSUserDefaults standardUserDefaults] setObject:[gemImage TIFFRepresentation] forKey:key];
175 if (i == 0) [iv1 setImage:gemImage];
176 if (i == 1) [iv2 setImage:gemImage];
177 if (i == 2) [iv3 setImage:gemImage];
178 if (i == 3) [iv4 setImage:gemImage];
179 if (i == 4) [iv5 setImage:gemImage];
180 if (i == 5) [iv6 setImage:gemImage];
181 if (i == 6) [iv7 setImage:gemImage];
184 useImportedGraphics = YES;
189 - (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender
191 //NSLog(@"prefsCustomBackgroundCheckboxAction");
193 if (sender!=prefsCustomBackgroundCheckbox)
195 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
196 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
200 - (IBAction)prefsSelectFolderButtonAction
202 NSOpenPanel *op=[NSOpenPanel openPanel];
204 //NSLog(@"prefsSelectFolderButtonAction");
205 [op setCanChooseDirectories:YES];
206 [op setCanChooseFiles:NO];
207 // get a sheet going to let the user pick a folder to scan for pictures
208 [op beginSheetForDirectory:[prefsCustomBackgroundFolderTextField stringValue] file:NULL types:NULL modalForWindow:prefsPanel modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
211 - (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem
213 if (aMenuItem == easyGameMenuItem)
214 return [easyGameButton isEnabled];
215 if (aMenuItem == hardGameMenuItem)
216 return [hardGameButton isEnabled];
217 if (aMenuItem == toughGameMenuItem)
218 return [toughGameButton isEnabled];
219 if (aMenuItem == freePlayMenuItem)
220 return [easyGameButton isEnabled];
221 if (aMenuItem == abortGameMenuItem)
222 return [abortGameButton isEnabled];
223 if (aMenuItem == pauseGameMenuItem)
224 return [pauseGameButton isEnabled];
226 // only allow viewing and reset of scores between games
228 if (aMenuItem == showHighScoresMenuItem)
229 return [easyGameButton isEnabled];
230 if (aMenuItem == resetHighScoresMenuItem)
231 return [easyGameButton isEnabled];
235 - (IBAction)startNewGame:(id)sender
237 //NSLog(@"gameController.startNewGame messaged gameView:%@",gameView);
239 [easyGameButton setEnabled:NO];
240 [hardGameButton setEnabled:NO];
241 [toughGameButton setEnabled:NO];
242 [abortGameButton setEnabled:YES];
243 [pauseGameButton setEnabled:YES];
249 if ((sender == easyGameButton) ||
250 (sender == easyGameMenuItem)) {
251 //NSLog(@"debug - hiScores = %@\n...hiScores.count = %d",hiScores,[hiScores count]);
253 gameTime = 600.0; // ten minutes
254 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
255 localizedStringForKey:@"EasyHighScoresHTML"
256 value:nil table:nil]];
258 // TODO: add else if?
259 if ((sender == hardGameButton) ||
260 (sender == hardGameMenuItem)) {
262 gameTime = 180.0; // three minutes
263 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
264 localizedStringForKey:@"HardHighScoresHTML"
265 value:nil table:nil]];
267 // TODO: add else if?
268 if ((sender == toughGameButton) ||
269 (sender == toughGameMenuItem)) {
271 gameTime = 90.0; // one and a half minutes
272 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
273 localizedStringForKey:@"ToughHighScoresHTML"
274 value:nil table:nil]];
277 if (sender==freePlayMenuItem)
280 gameTime = 3600.0; // one hour FWIW
281 freePlay = YES;// FREEPLAY
282 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
283 localizedStringForKey:@"FreePlayHighScoresHTML"
284 value:nil table:nil]];
287 freePlay = NO;// FREEPLAY
290 gameNames = [hiScores objectAtIndex:gameLevel*2];
291 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
292 [game wholeNewGameWithSpritesFrom:gameView.gemSpriteArray];
294 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game.score]];
295 [scoreTextField setNeedsDisplay:YES];
296 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game.bonusMultiplier]];
297 [bonusTextField setNeedsDisplay:YES];
300 [gameView setGame:game];
301 [gameView setLegend:nil];
302 [gameView setPaused:NO];
303 gameView.muted = muted;
304 [gameView setShowHint:!freePlay];// FREEPLAY
306 [timerView setTimerRunningEvery:0.5/gameSpeed
307 decrement:(0.5/gameTime)
309 whenRunOut:@selector(runOutOfTime)
310 whenRunOver:@selector(bonusAwarded)];
314 [timerView setDecrement:0.0];// FREEPLAY MW
315 [timerView setTimer:0.0];
318 [timerView setPaused:YES];
320 [gameView setLastMoveDate];
321 [self startAnimation:@selector(waitForFirstClick)];
324 - (IBAction)abortGame:(id)sender
326 #pragma unused (sender)
328 [abortGameButton setEnabled:NO];
330 [self togglePauseMode:self];
332 [pauseGameButton setEnabled:NO];
334 [self waitForFirstClick];
337 - (IBAction)receiveHiScoreName:(id)sender
339 #pragma unused (sender)
341 int score = [hiScorePanelScoreTextField intValue];
342 NSString *name = [hiScorePanelNameTextField stringValue];
344 [NSApp endSheet:hiScorePanel];
345 [hiScorePanel close];
347 //NSLog(@"receiving HiScoreName:%@ %d",name,score);
349 // reset arrays to gameLevel
350 gameNames = [hiScores objectAtIndex:gameLevel*2];
351 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
353 for (int i = 0; i < 10; i++) {
354 if (score > [[gameScores objectAtIndex:i] intValue]) {
355 [gameScores insertObject:[NSNumber numberWithInt:score] atIndex:i];
356 [gameScores removeObjectAtIndex:10];
358 [gameNames insertObject:name atIndex:i];
359 [gameNames removeObjectAtIndex:10];
364 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hiScores"]; // or it won't work!?!
365 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
367 //NSLog(@"written high-scores to preferences");
369 _gameState = GAMESTATE_GAMEOVER;
370 [gameView showHighScores:gameScores andNames:gameNames];
371 [gameView setLastMoveDate]; //reset timer so scores show for 20s
374 - (IBAction)togglePauseMode:(id)sender
376 if (sender == pauseGameButton) {
377 _paused = [pauseGameButton state];
383 [pauseGameButton setState:_paused];
384 [timerView setPaused:_paused];
387 [gameView setPaused:YES];
388 [gameView setHTMLLegend:[[NSBundle mainBundle]
389 localizedStringForKey:@"PausedHTML"
390 value:nil table:nil]];
391 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
392 localizedStringForKey:@"ContinueGameMenuItemTitle"
393 value:nil table:nil]];
397 [gameView setPaused:NO];
398 [gameView setLegend:nil];
399 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
400 localizedStringForKey:@"PauseGameMenuItemTitle"
401 value:nil table:nil]];
405 - (IBAction)toggleMute:(id)sender
407 if (sender == muteButton) {
408 muted = [muteButton state];
414 [muteButton setState:muted];
415 gameView.muted = muted;
419 [muteMenuItem setTitle:[[NSBundle mainBundle]
420 localizedStringForKey:@"UnMuteGameMenuItemTitle"
421 value:nil table:nil]];
423 [muteMenuItem setTitle:[[NSBundle mainBundle]
424 localizedStringForKey:@"MuteGameMenuItemTitle"
425 value:nil table:nil]];
429 - (IBAction)orderFrontAboutPanel:(id)sender
431 #pragma unused (sender)
433 //NSLog(@"GameController showAboutPanel called");
435 [NSBundle loadNibNamed:@"About" owner:self];
437 [aboutPanel setFrameAutosaveName:@"aboutPanel"];
438 [aboutPanel makeKeyAndOrderFront:self];
441 - (IBAction)orderFrontPreferencesPanel:(id)sender
443 #pragma unused (sender)
446 [NSBundle loadNibNamed:@"Preferences" owner:self];
449 [prefsStandardGraphicsButton setState:!useAlternateGraphics];
450 [prefsAlternateGraphicsButton setState:useAlternateGraphics];
452 [prefsCustomBackgroundCheckbox setState:useCustomBackgrounds];
453 [prefsCustomBackgroundFolderTextField setStringValue:customBackgroundFolderPath];
454 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
455 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
457 if ([[NSUserDefaults standardUserDefaults] dataForKey:@"tiffGemImage0"])
459 for (int i = 0; i < 7; i++) {
460 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
461 NSData *tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:key];
462 NSImage *gemImage = [[NSImage alloc] initWithData:tiffData];
463 if (i == 0) [iv1 setImage:gemImage];
464 if (i == 1) [iv2 setImage:gemImage];
465 if (i == 2) [iv3 setImage:gemImage];
466 if (i == 3) [iv4 setImage:gemImage];
467 if (i == 4) [iv5 setImage:gemImage];
468 if (i == 5) [iv6 setImage:gemImage];
469 if (i == 6) [iv7 setImage:gemImage];
474 [prefsPanel setFrameAutosaveName:@"prefsPanel"];
475 [prefsPanel makeKeyAndOrderFront:self];
478 - (IBAction)showHighScores:(id)sender
480 #pragma unused (sender)
482 // rotate which scores to show
484 gameNames = [hiScores objectAtIndex:gameLevel*2];
485 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
487 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
488 localizedStringForKey:@"EasyHighScoresHTML"
489 value:nil table:nil]];
490 else if (gameLevel==1)
491 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
492 localizedStringForKey:@"HardHighScoresHTML"
493 value:nil table:nil]];
494 else if (gameLevel==2)
495 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
496 localizedStringForKey:@"ToughHighScoresHTML"
497 value:nil table:nil]];
498 else if (gameLevel==3)
499 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
500 localizedStringForKey:@"FreePlayHighScoresHTML"
501 value:nil table:nil]];
502 gameLevel = (gameLevel +1)%4;
504 [gameView showHighScores:gameScores andNames:gameNames];
505 [gameView setLastMoveDate]; //reset timer so scores show for 20s
508 // TODO: remove (id)sender when not used? but only in header
509 - (IBAction)resetHighScores:(id)sender
511 #pragma unused (sender)
512 // don't rotate which scores to show
514 // blank the hi scores
517 hiScores = [[self makeBlankHiScoresWith:nil] retain];
518 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
520 [self showHighScores:self]; //call the show scores routine
523 - (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores
527 NSMutableArray *result = [NSMutableArray arrayWithCapacity:0];
529 if (oldScores) result = [NSMutableArray arrayWithArray:oldScores];
531 //for (i = 0; i < 3; i++)
532 while ([result count] < 8)
534 NSMutableArray *scores = [NSMutableArray arrayWithCapacity:0];
535 NSMutableArray *names = [NSMutableArray arrayWithCapacity:0];
536 for (j = 0; j < 10; j++)
538 [scores addObject:[NSNumber numberWithInt:1000]];
539 [names addObject:[[NSBundle mainBundle]
540 localizedStringForKey:@"AnonymousName"
541 value:nil table:nil]];
543 [result addObject:names];
544 [result addObject:scores];
546 return [NSArray arrayWithArray:result];
551 _gameState = GAMESTATE_GAMEOVER;
552 [abortGameButton setEnabled:NO];
553 [pauseGameButton setEnabled:NO];
555 [gameView setHTMLLegend:gameOverString];
557 [self startAnimation:@selector(waitForFirstClick)];
560 - (void)checkHiScores
563 // reset arrays with gameLevel
564 gameNames = [hiScores objectAtIndex:gameLevel*2];
565 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
566 for (i = 0; i < 10; i++)
568 if (game.score > [[gameScores objectAtIndex:i] intValue])
570 [hiScorePanelScoreTextField
571 setStringValue:[NSString stringWithFormat:@"%d", game.score]];
572 [NSApp beginSheet:hiScorePanel
573 modalForWindow:gameWindow
580 [gameView showHighScores:gameScores andNames:gameNames];
586 [gameView newBackground];
588 if (!muted) [[NSSound soundNamed:@"yes"] play];
590 if (!freePlay) { // FREEPLAY MW
591 [game increaseBonusMultiplier];
592 [timerView decrementMeter:0.5];
594 [game increaseBonusMultiplier];
595 [timerView decrementMeter:1];
598 if (gameSpeed < SPEED_LIMIT) // capping speed limit
599 gameSpeed = gameSpeed * 1.5;
600 //NSLog(@"...gamesSpeed %f",gameSpeed);
601 [timerView setTimerRunningEvery:0.5/gameSpeed
602 decrement:(0.5/gameTime)
604 whenRunOut:@selector(runOutOfTime)
605 whenRunOver:@selector(bonusAwarded)];
607 if (freePlay) [timerView setDecrement:0];// FREEPLAY
610 - (void)startAnimation:(SEL)andThenSelector
612 [animationTimerLock lock];
615 timer = [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL
617 selector:@selector(animate)
619 repeats:YES] retain];
621 whatNext = andThenSelector;
623 gameView.animating = YES;
625 [animationTimerLock unlock];
628 - (void)animationEnded
630 //NSLog(@"gameController.animationEnded messaged");
632 [animationTimerLock lock];
634 gameView.animating = NO;
636 [animationTimerLock unlock];
638 if (whatNext) [self performSelector:whatNext];
640 [gameView setNeedsDisplay:YES];
643 - (void)waitForNewGame
645 [self checkHiScores];
647 [game wholeNewGameWithSpritesFrom:gameView.gemSpriteArray];
648 [gameView setLegend:titleImage];
649 [easyGameButton setEnabled:YES];
650 [hardGameButton setEnabled:YES];
651 [toughGameButton setEnabled:YES];
652 [abortGameButton setEnabled:NO];
653 [pauseGameButton setEnabled:NO];
658 //NSLog(@"newBoard1");
660 [self startAnimation:@selector(newBoard2)];
667 //NSLog(@"newBoard2");
668 for (i = 0; i < 8; i++)
670 for (j = 0; j < 8; j++)
672 gem = [game gemAt:i:j];
673 //NSLog(@"..gem..%@",gem);
676 //[gem setImage:[gameView.gemImageArray objectAtIndex:r]];
677 gem.sprite = [gameView.gemSpriteArray objectAtIndex:r];
678 [gem setPositionOnBoard:i:j];
679 [gem setPositionOnScreen:i*48:(i+j+8)*48];
683 [gameView newBackground];
684 [gameView setLegend:nil];
685 [self startAnimation:@selector(testForThreesAgain)];
688 - (void)waitForFirstClick
690 //NSLog(@"waitForFirstClick");
691 /*- if (!freePlay) MW CHANGE -*/ [timerView setPaused:NO];
694 [timerView setTimer:0.5];
695 _gameState = GAMESTATE_GAMEOVER;
696 [game explodeGameOver];
697 [self startAnimation:@selector(waitForNewGame)];
700 if (![game boardHasMoves])
702 [timerView setPaused:YES];
703 [gameView setHTMLLegend:noMoreMovesString];
706 if (freePlay) [self startAnimation:@selector(runOutOfTime)];// FREEPLAY
707 else [self startAnimation:@selector(newBoard1)];// FREEPLAY
711 _gameState = GAMESTATE_AWAITINGFIRSTCLICK;
714 - (void)receiveClickAt:(int)x:(int)y
717 if ((x < 0)||(x > 383)||(y < 0)||(y > 383)) return;
718 if (_gameState == GAMESTATE_AWAITINGFIRSTCLICK)
720 chx1 = floor(x / 48);
721 chy1 = floor(y / 48);
722 _gameState = GAMESTATE_AWAITINGSECONDCLICK;
723 [gameView setNeedsDisplay:YES];
726 if (_gameState == GAMESTATE_AWAITINGSECONDCLICK)
728 chx2 = floor(x / 48);
729 chy2 = floor(y / 48);
730 if ((chx2 != chx1)^(chy2 != chy1)) // xor!
732 int d = (chx1-chx2)*(chx1-chx2)+(chy1-chy2)*(chy1-chy2);
733 //NSLog(@"square distance ==%d",d);
736 _gameState = GAMESTATE_FRACULATING;
737 [gameView setNeedsDisplay:YES];
738 [gameView setLastMoveDate];
739 /*- MW CHANGE if (!freePlay) -*/ [timerView setPaused:YES];
740 [self tryMoveSwapping:chx1:chy1 and:chx2:chy2];
744 // fall out of routine setting first click location
745 chx1 = floor(x / 48);
746 chy1 = floor(y / 48);
747 _gameState = GAMESTATE_AWAITINGSECONDCLICK;
748 [gameView setNeedsDisplay:YES];
752 - (void)tryMoveSwapping:(int)x1:(int)y1 and:(int)x2:(int)y2
755 int xx1, yy1, xx2, yy2;
756 //NSLog(@"tryMoveSwapping");
759 if (x1 < x2) { xx1 = x1; xx2 = x2; }
760 else { xx1 = x2; xx2 = x1; }
766 if (y1 < y2) { yy1 = y1; yy2 = y2; }
767 else { yy1 = y2; yy2 = y1; }
771 // store swap positions
772 chx1 = xx1; chy1 = yy1; chx2 = xx2; chy2 = yy2;
774 if (chx1 < chx2) // swapping horizontally
776 [[game gemAt:chx1:chy1] setVelocity:gemMoveSpeed:0:gemMoveSteps];
777 [[game gemAt:chx2:chy2] setVelocity:-gemMoveSpeed:0:gemMoveSteps];
779 else // swapping vertically
781 [[game gemAt:chx1:chy1] setVelocity:0:gemMoveSpeed:gemMoveSteps];
782 [[game gemAt:chx2:chy2] setVelocity:0:-gemMoveSpeed:gemMoveSteps];
784 [game swap:chx1:chy1 and:chx2:chy2];
785 _gameState = GAMESTATE_SWAPPING;
786 [self startAnimation:@selector(testForThrees)];
790 - (void)testForThrees
793 int oldScore = game.score;
794 //NSLog(@"testForThrees");
795 anyThrees = ([game testForThreeAt:chx1:chy1])|([game testForThreeAt:chx2:chy2]);
796 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game.score]];
797 [scoreTextField setNeedsDisplay:YES];
798 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game.bonusMultiplier]];
799 [bonusTextField setNeedsDisplay:YES];
800 if (game.score > oldScore) [timerView incrementMeter:[game collectFadedGems]/GEMS_FOR_BONUS];
802 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
807 //// repeat: remove threes
808 - (void)removeThreesAndReplaceGems
811 //NSLog(@"removeThreesAndReplaceGems");
813 [game removeFadedGemsAndReorganiseWithSpritesFrom:gameView.gemSpriteArray];
815 [self startAnimation:@selector(testForThreesAgain)]; // gems fall down
818 - (void)testForThreesAgain
820 int oldScore = game.score;
821 BOOL anyThrees = [game checkBoardForThrees];
823 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game.score]];
824 [scoreTextField setNeedsDisplay:YES];
826 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game.bonusMultiplier]];
827 [bonusTextField setNeedsDisplay:YES];
829 if (game.score > oldScore) {
830 [timerView incrementMeter:[game collectFadedGems]/GEMS_FOR_BONUS];
833 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
836 [self waitForFirstClick];
839 //// allow gems to fall
841 //// until there are no threes
847 if (!muted) [[NSSound soundNamed:@"no"] play];
850 if (chx1 < chx2) // swapping horizontally
852 [[game gemAt:chx1:chy1] setVelocity:4:0:12];
853 [[game gemAt:chx2:chy2] setVelocity:-4:0:12];
855 else // swapping vertically
857 [[game gemAt:chx1:chy1] setVelocity:0:4:12];
858 [[game gemAt:chx2:chy2] setVelocity:0:-4:12];
860 [game swap:chx1:chy1 and:chx2:chy2];
861 _gameState = GAMESTATE_SWAPPING;
862 [self startAnimation:@selector(waitForFirstClick)];
865 - (BOOL)useCustomBackgrounds {
866 return useCustomBackgrounds;
869 - (NSPoint)crossHair1Position {
870 return NSMakePoint(chx1 * 48,chy1 * 48);
873 - (NSPoint)crossHair2Position {
874 return NSMakePoint(chx2 * 48,chy2 * 48);