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
34 hiScores = [[NSUserDefaults standardUserDefaults] arrayForKey:@"hiScores"];
36 //NSLog(@"hiScores : %@",hiScores);
38 if ((!hiScores)||([hiScores count] < 8))
40 //NSLog(@"Creating High Score Tables");
41 hiScores = [self makeBlankHiScoresWith:hiScores];
42 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
46 noMoreMovesString = [[NSBundle mainBundle]
47 localizedStringForKey:@"NoMoreMovesHTML"
49 jeweltoyStartString = [[NSBundle mainBundle]
50 localizedStringForKey:@"JewelToyStartHTML"
52 gameOverString = [[NSBundle mainBundle]
53 localizedStringForKey:@"GameOverHTML"
55 titleImage = [NSImage imageNamed:@"title"];
57 gameNames = [hiScores objectAtIndex:0];
58 gameScores = [hiScores objectAtIndex:1];
60 game = [[Game alloc] init];
61 animationTimerLock = [[NSLock alloc] init];
63 gemMoveSize = GEM_GRAPHIC_SIZE;
64 gemMoveSpeed = GEM_MOVE_SPEED;
65 gemMoveSteps = gemMoveSize / gemMoveSpeed;
67 useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
68 useImportedGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useImportedGraphics"];
70 useCustomBackgrounds = [[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"];
71 customBackgroundFolderPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"];
72 if (!customBackgroundFolderPath)
73 customBackgroundFolderPath = [[NSBundle mainBundle] localizedStringForKey:@"PicturesFolderPath"
80 if (noMoreMovesString) [noMoreMovesString release];
81 if (jeweltoyStartString) [jeweltoyStartString release];
82 if (gameOverString) [gameOverString release];
83 if (game) [game release];
84 if (animationTimerLock) [animationTimerLock release];
85 if (timer) [timer release];
86 if (hiScores) [hiScores release];
92 [gameWindow setFrameAutosaveName:@"gameWindow"];
93 //useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
96 - (void)windowWillClose:(NSNotification *)aNotification
98 id obj = [aNotification object];
99 if (obj == aboutPanel)
101 //NSLog(@"Someone closed the 'About' window");
105 if (obj == prefsPanel)
107 //NSLog(@"Someone closed the 'Preferences' window");
108 useAlternateGraphics = [prefsAlternateGraphicsButton state];
109 [[NSUserDefaults standardUserDefaults] setBool:useAlternateGraphics
110 forKey:@"useAlternateGraphics"];
111 [[NSUserDefaults standardUserDefaults] setBool:useImportedGraphics
112 forKey:@"useImportedGraphics"];
114 useCustomBackgrounds = [prefsCustomBackgroundCheckbox state];
115 [[NSUserDefaults standardUserDefaults] setBool:useCustomBackgrounds
116 forKey:@"useCustomBackgrounds"];
117 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"customBackgroundFolderPath"];
118 [[NSUserDefaults standardUserDefaults] setObject:[prefsCustomBackgroundFolderTextField stringValue]
119 forKey:@"customBackgroundFolderPath"];
122 //[gameView loadImageArray];
123 [gameView graphicSetUp];
124 [gameView newBackground];
125 if (game) [game setSpritesFrom:[gameView spriteArray]];
126 [gameView setNeedsDisplay:YES];
131 if (obj == gameWindow)
133 //NSLog(@"Someone closed the window - shutting down JewelToy");
134 [NSApp terminate:self];
139 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
140 [prefsCustomBackgroundFolderTextField setStringValue:[[sheet filenames] objectAtIndex:0]];
143 // TODO: move algorithm to its own method
144 - (IBAction)prefsGraphicDropAction:(id)sender
147 // slice and dice importedImage, saving images to defaults
149 NSImage *importedImage = [prefsAlternateGraphicsImageView image];
153 NSRect cropRect = NSMakeRect(0.0,0.0,[importedImage size].width/7.0,[importedImage size].height);
154 NSRect gemRect = NSMakeRect(0.0,0.0,48.0,48.0);
155 NSSize imageSize = NSMakeSize(48.0,48.0);
156 for (i = 0; i < 7; i++)
158 NSImage *gemImage = [[NSImage alloc] initWithSize:imageSize];
159 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
160 cropRect.origin.x = i * [importedImage size].width/7.0;
161 [gemImage lockFocus];
162 [[NSColor clearColor] set];
164 [importedImage drawInRect:gemRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0];
165 [gemImage unlockFocus];
166 [[NSUserDefaults standardUserDefaults] setObject:[gemImage TIFFRepresentation] forKey:key];
167 if (i == 0) [iv1 setImage:gemImage];
168 if (i == 1) [iv2 setImage:gemImage];
169 if (i == 2) [iv3 setImage:gemImage];
170 if (i == 3) [iv4 setImage:gemImage];
171 if (i == 4) [iv5 setImage:gemImage];
172 if (i == 5) [iv6 setImage:gemImage];
173 if (i == 6) [iv7 setImage:gemImage];
176 useImportedGraphics = YES;
181 - (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender
183 //NSLog(@"prefsCustomBackgroundCheckboxAction");
185 if (sender!=prefsCustomBackgroundCheckbox)
187 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
188 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
192 - (IBAction)prefsSelectFolderButtonAction:(id)sender
194 NSOpenPanel *op=[NSOpenPanel openPanel];
196 //NSLog(@"prefsSelectFolderButtonAction");
197 [op setCanChooseDirectories:YES];
198 [op setCanChooseFiles:NO];
199 // get a sheet going to let the user pick a folder to scan for pictures
200 [op beginSheetForDirectory:[prefsCustomBackgroundFolderTextField stringValue] file:NULL types:NULL modalForWindow:prefsPanel modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
203 - (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem
205 if (aMenuItem == easyGameMenuItem)
206 return [easyGameButton isEnabled];
207 if (aMenuItem == hardGameMenuItem)
208 return [hardGameButton isEnabled];
209 if (aMenuItem == toughGameMenuItem)
210 return [toughGameButton isEnabled];
211 if (aMenuItem == freePlayMenuItem)
212 return [easyGameButton isEnabled];
213 if (aMenuItem == abortGameMenuItem)
214 return [abortGameButton isEnabled];
215 if (aMenuItem == pauseGameMenuItem)
216 return [pauseGameButton isEnabled];
218 // only allow viewing and reset of scores between games
220 if (aMenuItem == showHighScoresMenuItem)
221 return [easyGameButton isEnabled];
222 if (aMenuItem == resetHighScoresMenuItem)
223 return [easyGameButton isEnabled];
227 - (IBAction)startNewGame:(id)sender
229 //NSLog(@"gameController.startNewGame messaged gameView:%@",gameView);
231 [easyGameButton setEnabled:NO];
232 [hardGameButton setEnabled:NO];
233 [toughGameButton setEnabled:NO];
234 [abortGameButton setEnabled:YES];
235 [pauseGameButton setEnabled:YES];
241 if ((sender==easyGameButton)||(sender==easyGameMenuItem))
243 //NSLog(@"debug - hiScores = %@\n...hiScores.count = %d",hiScores,[hiScores count]);
245 gameTime = 600.0; // ten minutes
246 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
247 localizedStringForKey:@"EasyHighScoresHTML"
248 value:nil table:nil]];
250 if ((sender==hardGameButton)||(sender==hardGameMenuItem))
253 gameTime = 180.0; // three minutes
254 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
255 localizedStringForKey:@"HardHighScoresHTML"
256 value:nil table:nil]];
259 if ((sender==toughGameButton)||(sender==toughGameMenuItem))
262 gameTime = 90.0; // one and a half minutes
263 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
264 localizedStringForKey:@"ToughHighScoresHTML"
265 value:nil table:nil]];
267 if (sender==freePlayMenuItem)
270 gameTime = 3600.0; // one hour FWIW
271 freePlay = YES;// FREEPLAY
272 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
273 localizedStringForKey:@"FreePlayHighScoresHTML"
274 value:nil table:nil]];
277 freePlay = NO;// FREEPLAY
278 gameNames = [hiScores objectAtIndex:gameLevel*2];
279 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
280 [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
283 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game._score]];
284 [scoreTextField setNeedsDisplay:YES];
285 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game._bonusMultiplier]];
286 [bonusTextField setNeedsDisplay:YES];
289 [game setMuted:muted];
290 [gameView setGame:game];
291 [gameView setLegend:nil];
292 [gameView setPaused:NO];
293 [gameView setMuted:muted];
294 [gameView setShowHint:!freePlay];// FREEPLAY
296 [timerView setTimerRunningEvery:0.5/gameSpeed
297 decrement:(0.5/gameTime)
299 whenRunOut:@selector(runOutOfTime)
300 whenRunOver:@selector(bonusAwarded)];
304 [timerView setDecrement:0.0];// FREEPLAY MW
305 [timerView setTimer:0.0];
308 [timerView setPaused:YES];
310 [gameView setLastMoveDate];
311 [self startAnimation:@selector(waitForFirstClick)];
314 - (IBAction)abortGame:(id)sender
316 [abortGameButton setEnabled:NO];
317 if (paused) [self togglePauseMode:self];
318 [pauseGameButton setEnabled:NO];
320 [self waitForFirstClick];
322 - (IBAction)receiveHiScoreName:(id)sender
325 int score = [hiScorePanelScoreTextField intValue];
326 NSString *name = [hiScorePanelNameTextField stringValue];
328 [NSApp endSheet:hiScorePanel];
329 [hiScorePanel close];
331 //NSLog(@"receiving HiScoreName:%@ %d",name,score);
333 // reset arrays to gameLevel
334 gameNames = [hiScores objectAtIndex:gameLevel*2];
335 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
337 for (i = 0; i < 10; i++)
339 if (score > [[gameScores objectAtIndex:i] intValue])
341 [gameScores insertObject:[NSNumber numberWithInt:score] atIndex:i];
342 [gameScores removeObjectAtIndex:10];
343 [gameNames insertObject:name atIndex:i];
344 [gameNames removeObjectAtIndex:10];
349 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hiScores"]; // or it won't work!?!
350 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
352 //NSLog(@"written high-scores to preferences");
354 gameState = GAMESTATE_GAMEOVER;
355 [gameView showHighScores:gameScores andNames:gameNames];
356 [gameView setLastMoveDate]; //reset timer so scores show for 20s
359 - (IBAction)togglePauseMode:(id)sender
361 //NSLog(@"Pause game toggled, sender state is %d",[sender state]);
362 if (sender == pauseGameButton)
363 paused = [sender state];
367 [pauseGameButton setState:paused];
368 [timerView setPaused:paused];
371 [gameView setPaused:YES];
372 [gameView setHTMLLegend:[[NSBundle mainBundle]
373 localizedStringForKey:@"PausedHTML"
374 value:nil table:nil]];
375 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
376 localizedStringForKey:@"ContinueGameMenuItemTitle"
377 value:nil table:nil]];
381 [gameView setPaused:NO];
382 [gameView setLegend:nil];
383 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
384 localizedStringForKey:@"PauseGameMenuItemTitle"
385 value:nil table:nil]];
389 - (IBAction)toggleMute:(id)sender
391 if (sender == muteButton)
392 muted = [sender state];
396 [muteButton setState:muted];
397 [gameView setMuted:muted];
398 [game setMuted:muted];
401 [muteMenuItem setTitle:[[NSBundle mainBundle]
402 localizedStringForKey:@"UnMuteGameMenuItemTitle"
403 value:nil table:nil]];
405 [muteMenuItem setTitle:[[NSBundle mainBundle]
406 localizedStringForKey:@"MuteGameMenuItemTitle"
407 value:nil table:nil]];
411 - (IBAction)orderFrontAboutPanel:(id)sender
413 //NSLog(@"GameController showAboutPanel called");
415 [NSBundle loadNibNamed:@"About" owner:self];
416 [aboutPanel setFrameAutosaveName:@"aboutPanel"];
417 [aboutPanel makeKeyAndOrderFront:self];
420 - (IBAction)orderFrontPreferencesPanel:(id)sender
423 [NSBundle loadNibNamed:@"Preferences" owner:self];
425 [prefsStandardGraphicsButton setState:!useAlternateGraphics];
426 [prefsAlternateGraphicsButton setState:useAlternateGraphics];
428 [prefsCustomBackgroundCheckbox setState:useCustomBackgrounds];
429 [prefsCustomBackgroundFolderTextField setStringValue:customBackgroundFolderPath];
430 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
431 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
433 if ([[NSUserDefaults standardUserDefaults] dataForKey:@"tiffGemImage0"])
436 for (i = 0; i < 7; i++)
438 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
439 NSData *tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:key];
440 NSImage *gemImage = [[NSImage alloc] initWithData:tiffData];
441 if (i == 0) [iv1 setImage:gemImage];
442 if (i == 1) [iv2 setImage:gemImage];
443 if (i == 2) [iv3 setImage:gemImage];
444 if (i == 3) [iv4 setImage:gemImage];
445 if (i == 4) [iv5 setImage:gemImage];
446 if (i == 5) [iv6 setImage:gemImage];
447 if (i == 6) [iv7 setImage:gemImage];
452 [prefsPanel setFrameAutosaveName:@"prefsPanel"];
453 [prefsPanel makeKeyAndOrderFront:self];
456 - (IBAction)showHighScores:(id)sender
458 // rotate which scores to show
460 gameNames = [hiScores objectAtIndex:gameLevel*2];
461 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
463 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
464 localizedStringForKey:@"EasyHighScoresHTML"
465 value:nil table:nil]];
466 else if (gameLevel==1)
467 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
468 localizedStringForKey:@"HardHighScoresHTML"
469 value:nil table:nil]];
470 else if (gameLevel==2)
471 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
472 localizedStringForKey:@"ToughHighScoresHTML"
473 value:nil table:nil]];
474 else if (gameLevel==3)
475 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
476 localizedStringForKey:@"FreePlayHighScoresHTML"
477 value:nil table:nil]];
478 gameLevel = (gameLevel +1)%4;
480 [gameView showHighScores:gameScores andNames:gameNames];
481 [gameView setLastMoveDate]; //reset timer so scores show for 20s
484 - (IBAction)resetHighScores:(id)sender
486 // don't rotate which scores to show
488 // blank the hi scores
491 hiScores = [[self makeBlankHiScoresWith:nil] retain];
492 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
494 [self showHighScores:sender]; //call the show scores routine
497 - (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores
501 NSMutableArray *result = [NSMutableArray arrayWithCapacity:0];
503 if (oldScores) result = [NSMutableArray arrayWithArray:oldScores];
505 //for (i = 0; i < 3; i++)
506 while ([result count] < 8)
508 NSMutableArray *scores = [NSMutableArray arrayWithCapacity:0];
509 NSMutableArray *names = [NSMutableArray arrayWithCapacity:0];
510 for (j = 0; j < 10; j++)
512 [scores addObject:[NSNumber numberWithInt:1000]];
513 [names addObject:[[NSBundle mainBundle]
514 localizedStringForKey:@"AnonymousName"
515 value:nil table:nil]];
517 [result addObject:names];
518 [result addObject:scores];
520 return [NSArray arrayWithArray:result];
525 gameState = GAMESTATE_GAMEOVER;
526 [abortGameButton setEnabled:NO];
527 [pauseGameButton setEnabled:NO];
529 [gameView setHTMLLegend:gameOverString];
531 [self startAnimation:@selector(waitForFirstClick)];
534 - (void)checkHiScores
537 // reset arrays with gameLevel
538 gameNames = [hiScores objectAtIndex:gameLevel*2];
539 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
540 for (i = 0; i < 10; i++)
542 if (game._score > [[gameScores objectAtIndex:i] intValue])
544 [hiScorePanelScoreTextField
545 setStringValue:[NSString stringWithFormat:@"%d", game._score]];
546 [NSApp beginSheet:hiScorePanel
547 modalForWindow:gameWindow
554 [gameView showHighScores:gameScores andNames:gameNames];
560 [gameView newBackground];
562 if (!muted) [[NSSound soundNamed:@"yes"] play];
564 if (!freePlay) { // FREEPLAY MW
565 [game increaseBonusMultiplier];
566 [timerView decrementMeter:0.5];
568 [game increaseBonusMultiplier];
569 [timerView decrementMeter:1];
572 if (gameSpeed < SPEED_LIMIT) // capping speed limit
573 gameSpeed = gameSpeed * 1.5;
574 //NSLog(@"...gamesSpeed %f",gameSpeed);
575 [timerView setTimerRunningEvery:0.5/gameSpeed
576 decrement:(0.5/gameTime)
578 whenRunOut:@selector(runOutOfTime)
579 whenRunOver:@selector(bonusAwarded)];
581 if (freePlay) [timerView setDecrement:0];// FREEPLAY
584 - (void)startAnimation:(SEL)andThenSelector
586 [animationTimerLock lock];
589 timer = [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL
591 selector:@selector(animate)
593 repeats:YES] retain];
595 whatNext = andThenSelector;
597 gameView._animating = YES;
599 [animationTimerLock unlock];
602 - (void)animationEnded
604 //NSLog(@"gameController.animationEnded messaged");
606 [animationTimerLock lock];
608 gameView._animating = NO;
610 [animationTimerLock unlock];
612 if (whatNext) [self performSelector:whatNext];
614 [gameView setNeedsDisplay:YES];
617 - (void)waitForNewGame
619 [self checkHiScores];
621 [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
622 [gameView setLegend:titleImage];
623 [easyGameButton setEnabled:YES];
624 [hardGameButton setEnabled:YES];
625 [toughGameButton setEnabled:YES];
626 [abortGameButton setEnabled:NO];
627 [pauseGameButton setEnabled:NO];
632 //NSLog(@"newBoard1");
634 [self startAnimation:@selector(newBoard2)];
641 //NSLog(@"newBoard2");
642 for (i = 0; i < 8; i++)
644 for (j = 0; j < 8; j++)
646 gem = [game gemAt:i:j];
647 //NSLog(@"..gem..%@",gem);
650 //[gem setImage:[[gameView imageArray] objectAtIndex:r]];
651 [gem setSprite:[[gameView spriteArray] objectAtIndex:r]];
652 [gem setPositionOnBoard:i:j];
653 [gem setPositionOnScreen:i*48:(i+j+8)*48];
657 [gameView newBackground];
658 [gameView setLegend:nil];
659 [self startAnimation:@selector(testForThreesAgain)];
662 - (void)waitForFirstClick
664 //NSLog(@"waitForFirstClick");
665 /*- if (!freePlay) MW CHANGE -*/ [timerView setPaused:NO];
668 [timerView setTimer:0.5];
669 gameState = GAMESTATE_GAMEOVER;
670 [game explodeGameOver];
671 [self startAnimation:@selector(waitForNewGame)];
674 if (![game boardHasMoves])
676 [timerView setPaused:YES];
677 [gameView setHTMLLegend:noMoreMovesString];
680 if (freePlay) [self startAnimation:@selector(runOutOfTime)];// FREEPLAY
681 else [self startAnimation:@selector(newBoard1)];// FREEPLAY
685 gameState = GAMESTATE_AWAITINGFIRSTCLICK;
688 - (void)receiveClickAt:(int)x:(int)y
691 if ((x < 0)||(x > 383)||(y < 0)||(y > 383)) return;
692 if (gameState == GAMESTATE_AWAITINGFIRSTCLICK)
694 chx1 = floor(x / 48);
695 chy1 = floor(y / 48);
696 gameState = GAMESTATE_AWAITINGSECONDCLICK;
697 [gameView setNeedsDisplay:YES];
700 if (gameState == GAMESTATE_AWAITINGSECONDCLICK)
702 chx2 = floor(x / 48);
703 chy2 = floor(y / 48);
704 if ((chx2 != chx1)^(chy2 != chy1)) // xor!
706 int d = (chx1-chx2)*(chx1-chx2)+(chy1-chy2)*(chy1-chy2);
707 //NSLog(@"square distance ==%d",d);
710 gameState = GAMESTATE_FRACULATING;
711 [gameView setNeedsDisplay:YES];
712 [gameView setLastMoveDate];
713 /*- MW CHANGE if (!freePlay) -*/ [timerView setPaused:YES];
714 [self tryMoveSwapping:chx1:chy1 and:chx2:chy2];
718 // fall out of routine setting first click location
719 chx1 = floor(x / 48);
720 chy1 = floor(y / 48);
721 gameState = GAMESTATE_AWAITINGSECONDCLICK;
722 [gameView setNeedsDisplay:YES];
726 - (void)tryMoveSwapping:(int)x1:(int)y1 and:(int)x2:(int)y2
729 int xx1, yy1, xx2, yy2;
730 //NSLog(@"tryMoveSwapping");
733 if (x1 < x2) { xx1 = x1; xx2 = x2; }
734 else { xx1 = x2; xx2 = x1; }
740 if (y1 < y2) { yy1 = y1; yy2 = y2; }
741 else { yy1 = y2; yy2 = y1; }
745 // store swap positions
746 chx1 = xx1; chy1 = yy1; chx2 = xx2; chy2 = yy2;
748 if (chx1 < chx2) // swapping horizontally
750 [[game gemAt:chx1:chy1] setVelocity:gemMoveSpeed:0:gemMoveSteps];
751 [[game gemAt:chx2:chy2] setVelocity:-gemMoveSpeed:0:gemMoveSteps];
753 else // swapping vertically
755 [[game gemAt:chx1:chy1] setVelocity:0:gemMoveSpeed:gemMoveSteps];
756 [[game gemAt:chx2:chy2] setVelocity:0:-gemMoveSpeed:gemMoveSteps];
758 [game swap:chx1:chy1 and:chx2:chy2];
759 gameState = GAMESTATE_SWAPPING;
760 [self startAnimation:@selector(testForThrees)];
764 - (void)testForThrees
767 int oldScore = game._score;
768 //NSLog(@"testForThrees");
769 anyThrees = ([game testForThreeAt:chx1:chy1])|([game testForThreeAt:chx2:chy2]);
770 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game._score]];
771 [scoreTextField setNeedsDisplay:YES];
772 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game._bonusMultiplier]];
773 [bonusTextField setNeedsDisplay:YES];
774 if (game._score > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS];
776 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
781 //// repeat: remove threes
782 - (void)removeThreesAndReplaceGems
785 //NSLog(@"removeThreesAndReplaceGems");
787 [game removeFadedGemsAndReorganiseWithSpritesFrom:[gameView spriteArray]];
789 [self startAnimation:@selector(testForThreesAgain)]; // gems fall down
792 - (void)testForThreesAgain
795 int oldScore = game._score;
796 //NSLog(@"testForThreesAgain");
797 anyThrees = [game checkBoardForThrees];
798 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game._score]];
799 [scoreTextField setNeedsDisplay:YES];
800 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game._bonusMultiplier]];
801 [bonusTextField setNeedsDisplay:YES];
802 if (game._score > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS];
804 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
806 [self waitForFirstClick];
808 //// allow gems to fall
810 //// until there are no threes
816 if (!muted) [[NSSound soundNamed:@"no"] play];
819 if (chx1 < chx2) // swapping horizontally
821 [[game gemAt:chx1:chy1] setVelocity:4:0:12];
822 [[game gemAt:chx2:chy2] setVelocity:-4:0:12];
824 else // swapping vertically
826 [[game gemAt:chx1:chy1] setVelocity:0:4:12];
827 [[game gemAt:chx2:chy2] setVelocity:0:-4:12];
829 [game swap:chx1:chy1 and:chx2:chy2];
830 gameState = GAMESTATE_SWAPPING;
831 [self startAnimation:@selector(waitForFirstClick)];
838 - (BOOL) gameIsPaused {
842 - (BOOL) useCustomBackgrounds {
843 return useCustomBackgrounds;
846 - (NSPoint) crossHair1Position {
847 return NSMakePoint(chx1*48,chy1*48);
850 - (NSPoint) crossHair2Position
852 return NSMakePoint(chx2*48,chy2*48);