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;
39 hiScores = [[NSUserDefaults standardUserDefaults] arrayForKey:@"hiScores"];
41 //NSLog(@"hiScores : %@",hiScores);
43 if ((!hiScores)||([hiScores count] < 8))
45 //NSLog(@"Creating High Score Tables");
46 hiScores = [self makeBlankHiScoresWith:hiScores];
47 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
51 noMoreMovesString = [[NSBundle mainBundle]
52 localizedStringForKey:@"NoMoreMovesHTML"
54 jeweltoyStartString = [[NSBundle mainBundle]
55 localizedStringForKey:@"JewelToyStartHTML"
57 gameOverString = [[NSBundle mainBundle]
58 localizedStringForKey:@"GameOverHTML"
60 titleImage = [NSImage imageNamed:@"title"];
62 gameNames = [hiScores objectAtIndex:0];
63 gameScores = [hiScores objectAtIndex:1];
65 game = [[Game alloc] init];
66 animationTimerLock = [[NSLock alloc] init];
68 gemMoveSize = GEM_GRAPHIC_SIZE;
69 gemMoveSpeed = GEM_MOVE_SPEED;
70 gemMoveSteps = gemMoveSize / gemMoveSpeed;
72 useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
73 useImportedGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useImportedGraphics"];
75 useCustomBackgrounds = [[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"];
76 customBackgroundFolderPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"];
77 if (!customBackgroundFolderPath)
78 customBackgroundFolderPath = [[NSBundle mainBundle] localizedStringForKey:@"PicturesFolderPath"
85 if (noMoreMovesString) [noMoreMovesString release];
86 if (jeweltoyStartString) [jeweltoyStartString release];
87 if (gameOverString) [gameOverString release];
88 if (game) [game release];
89 if (animationTimerLock) [animationTimerLock release];
90 if (timer) [timer release];
91 if (hiScores) [hiScores release];
97 [gameWindow setFrameAutosaveName:@"gameWindow"];
98 //useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
101 - (void)windowWillClose:(NSNotification *)aNotification
103 id obj = [aNotification object];
104 if (obj == aboutPanel)
106 //NSLog(@"Someone closed the 'About' window");
110 if (obj == prefsPanel)
112 //NSLog(@"Someone closed the 'Preferences' window");
113 useAlternateGraphics = [prefsAlternateGraphicsButton state];
114 [[NSUserDefaults standardUserDefaults] setBool:useAlternateGraphics
115 forKey:@"useAlternateGraphics"];
116 [[NSUserDefaults standardUserDefaults] setBool:useImportedGraphics
117 forKey:@"useImportedGraphics"];
119 useCustomBackgrounds = [prefsCustomBackgroundCheckbox state];
120 [[NSUserDefaults standardUserDefaults] setBool:useCustomBackgrounds
121 forKey:@"useCustomBackgrounds"];
122 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"customBackgroundFolderPath"];
123 [[NSUserDefaults standardUserDefaults] setObject:[prefsCustomBackgroundFolderTextField stringValue]
124 forKey:@"customBackgroundFolderPath"];
127 //[gameView loadImageArray];
128 [gameView graphicSetUp];
129 [gameView newBackground];
130 if (game) [game setSpritesFrom:[gameView spriteArray]];
131 [gameView setNeedsDisplay:YES];
136 if (obj == gameWindow)
138 //NSLog(@"Someone closed the window - shutting down JewelToy");
139 [NSApp terminate:self];
144 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
145 #pragma unused (returnCode, contextInfo)
146 [prefsCustomBackgroundFolderTextField setStringValue:[[sheet filenames] objectAtIndex:0]];
149 // TODO: move algorithm to its own method
150 - (IBAction)prefsGraphicDropAction
153 // slice and dice importedImage, saving images to defaults
155 NSImage *importedImage = [prefsAlternateGraphicsImageView image];
159 NSRect cropRect = NSMakeRect(0.0,0.0,[importedImage size].width/7.0,[importedImage size].height);
160 NSRect gemRect = NSMakeRect(0.0,0.0,48.0,48.0);
161 NSSize imageSize = NSMakeSize(48.0,48.0);
162 for (i = 0; i < 7; i++)
164 NSImage *gemImage = [[NSImage alloc] initWithSize:imageSize];
165 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
166 cropRect.origin.x = i * [importedImage size].width/7.0;
167 [gemImage lockFocus];
168 [[NSColor clearColor] set];
170 [importedImage drawInRect:gemRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0];
171 [gemImage unlockFocus];
172 [[NSUserDefaults standardUserDefaults] setObject:[gemImage TIFFRepresentation] forKey:key];
173 if (i == 0) [iv1 setImage:gemImage];
174 if (i == 1) [iv2 setImage:gemImage];
175 if (i == 2) [iv3 setImage:gemImage];
176 if (i == 3) [iv4 setImage:gemImage];
177 if (i == 4) [iv5 setImage:gemImage];
178 if (i == 5) [iv6 setImage:gemImage];
179 if (i == 6) [iv7 setImage:gemImage];
182 useImportedGraphics = YES;
187 - (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender
189 //NSLog(@"prefsCustomBackgroundCheckboxAction");
191 if (sender!=prefsCustomBackgroundCheckbox)
193 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
194 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
198 - (IBAction)prefsSelectFolderButtonAction
200 NSOpenPanel *op=[NSOpenPanel openPanel];
202 //NSLog(@"prefsSelectFolderButtonAction");
203 [op setCanChooseDirectories:YES];
204 [op setCanChooseFiles:NO];
205 // get a sheet going to let the user pick a folder to scan for pictures
206 [op beginSheetForDirectory:[prefsCustomBackgroundFolderTextField stringValue] file:NULL types:NULL modalForWindow:prefsPanel modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
209 - (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem
211 if (aMenuItem == easyGameMenuItem)
212 return [easyGameButton isEnabled];
213 if (aMenuItem == hardGameMenuItem)
214 return [hardGameButton isEnabled];
215 if (aMenuItem == toughGameMenuItem)
216 return [toughGameButton isEnabled];
217 if (aMenuItem == freePlayMenuItem)
218 return [easyGameButton isEnabled];
219 if (aMenuItem == abortGameMenuItem)
220 return [abortGameButton isEnabled];
221 if (aMenuItem == pauseGameMenuItem)
222 return [pauseGameButton isEnabled];
224 // only allow viewing and reset of scores between games
226 if (aMenuItem == showHighScoresMenuItem)
227 return [easyGameButton isEnabled];
228 if (aMenuItem == resetHighScoresMenuItem)
229 return [easyGameButton isEnabled];
233 - (IBAction)startNewGame:(id)sender
235 //NSLog(@"gameController.startNewGame messaged gameView:%@",gameView);
237 [easyGameButton setEnabled:NO];
238 [hardGameButton setEnabled:NO];
239 [toughGameButton setEnabled:NO];
240 [abortGameButton setEnabled:YES];
241 [pauseGameButton setEnabled:YES];
247 if ((sender == easyGameButton) ||
248 (sender == easyGameMenuItem)) {
249 //NSLog(@"debug - hiScores = %@\n...hiScores.count = %d",hiScores,[hiScores count]);
251 gameTime = 600.0; // ten minutes
252 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
253 localizedStringForKey:@"EasyHighScoresHTML"
254 value:nil table:nil]];
256 // TODO: add else if?
257 if ((sender == hardGameButton) ||
258 (sender == hardGameMenuItem)) {
260 gameTime = 180.0; // three minutes
261 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
262 localizedStringForKey:@"HardHighScoresHTML"
263 value:nil table:nil]];
265 // TODO: add else if?
266 if ((sender == toughGameButton) ||
267 (sender == toughGameMenuItem)) {
269 gameTime = 90.0; // one and a half minutes
270 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
271 localizedStringForKey:@"ToughHighScoresHTML"
272 value:nil table:nil]];
275 if (sender==freePlayMenuItem)
278 gameTime = 3600.0; // one hour FWIW
279 freePlay = YES;// FREEPLAY
280 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
281 localizedStringForKey:@"FreePlayHighScoresHTML"
282 value:nil table:nil]];
285 freePlay = NO;// FREEPLAY
288 gameNames = [hiScores objectAtIndex:gameLevel*2];
289 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
290 [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
292 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game.score]];
293 [scoreTextField setNeedsDisplay:YES];
294 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game.bonusMultiplier]];
295 [bonusTextField setNeedsDisplay:YES];
297 [game setMuted:muted];
298 [gameView setGame:game];
299 [gameView setLegend:nil];
300 [gameView setPaused:NO];
301 [gameView setMuted:muted];
302 [gameView setShowHint:!freePlay];// FREEPLAY
304 [timerView setTimerRunningEvery:0.5/gameSpeed
305 decrement:(0.5/gameTime)
307 whenRunOut:@selector(runOutOfTime)
308 whenRunOver:@selector(bonusAwarded)];
312 [timerView setDecrement:0.0];// FREEPLAY MW
313 [timerView setTimer:0.0];
316 [timerView setPaused:YES];
318 [gameView setLastMoveDate];
319 [self startAnimation:@selector(waitForFirstClick)];
322 - (IBAction)abortGame
324 [abortGameButton setEnabled:NO];
325 if (paused) [self togglePauseMode:self];
326 [pauseGameButton setEnabled:NO];
328 [self waitForFirstClick];
331 - (IBAction)receiveHiScoreName
333 int score = [hiScorePanelScoreTextField intValue];
334 NSString *name = [hiScorePanelNameTextField stringValue];
336 [NSApp endSheet:hiScorePanel];
337 [hiScorePanel close];
339 //NSLog(@"receiving HiScoreName:%@ %d",name,score);
341 // reset arrays to gameLevel
342 gameNames = [hiScores objectAtIndex:gameLevel*2];
343 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
345 for (int i = 0; i < 10; i++) {
346 if (score > [[gameScores objectAtIndex:i] intValue]) {
347 [gameScores insertObject:[NSNumber numberWithInt:score] atIndex:i];
348 [gameScores removeObjectAtIndex:10];
350 [gameNames insertObject:name atIndex:i];
351 [gameNames removeObjectAtIndex:10];
356 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hiScores"]; // or it won't work!?!
357 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
359 //NSLog(@"written high-scores to preferences");
361 _gameState = GAMESTATE_GAMEOVER;
362 [gameView showHighScores:gameScores andNames:gameNames];
363 [gameView setLastMoveDate]; //reset timer so scores show for 20s
366 - (IBAction)togglePauseMode:(id)sender
368 //NSLog(@"Pause game toggled, sender state is %d",[sender state]);
369 if (sender == pauseGameButton)
370 paused = [sender state];
374 [pauseGameButton setState:paused];
375 [timerView setPaused:paused];
378 [gameView setPaused:YES];
379 [gameView setHTMLLegend:[[NSBundle mainBundle]
380 localizedStringForKey:@"PausedHTML"
381 value:nil table:nil]];
382 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
383 localizedStringForKey:@"ContinueGameMenuItemTitle"
384 value:nil table:nil]];
388 [gameView setPaused:NO];
389 [gameView setLegend:nil];
390 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
391 localizedStringForKey:@"PauseGameMenuItemTitle"
392 value:nil table:nil]];
396 - (IBAction)toggleMute:(id)sender
398 if (sender == muteButton)
399 muted = [sender state];
403 [muteButton setState:muted];
404 [gameView setMuted:muted];
405 [game setMuted:muted];
408 [muteMenuItem setTitle:[[NSBundle mainBundle]
409 localizedStringForKey:@"UnMuteGameMenuItemTitle"
410 value:nil table:nil]];
412 [muteMenuItem setTitle:[[NSBundle mainBundle]
413 localizedStringForKey:@"MuteGameMenuItemTitle"
414 value:nil table:nil]];
418 - (IBAction)orderFrontAboutPanel
420 //NSLog(@"GameController showAboutPanel called");
422 [NSBundle loadNibNamed:@"About" owner:self];
424 [aboutPanel setFrameAutosaveName:@"aboutPanel"];
425 [aboutPanel makeKeyAndOrderFront:self];
428 - (IBAction)orderFrontPreferencesPanel
431 [NSBundle loadNibNamed:@"Preferences" owner:self];
434 [prefsStandardGraphicsButton setState:!useAlternateGraphics];
435 [prefsAlternateGraphicsButton setState:useAlternateGraphics];
437 [prefsCustomBackgroundCheckbox setState:useCustomBackgrounds];
438 [prefsCustomBackgroundFolderTextField setStringValue:customBackgroundFolderPath];
439 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
440 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
442 if ([[NSUserDefaults standardUserDefaults] dataForKey:@"tiffGemImage0"])
444 for (int i = 0; i < 7; i++) {
445 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
446 NSData *tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:key];
447 NSImage *gemImage = [[NSImage alloc] initWithData:tiffData];
448 if (i == 0) [iv1 setImage:gemImage];
449 if (i == 1) [iv2 setImage:gemImage];
450 if (i == 2) [iv3 setImage:gemImage];
451 if (i == 3) [iv4 setImage:gemImage];
452 if (i == 4) [iv5 setImage:gemImage];
453 if (i == 5) [iv6 setImage:gemImage];
454 if (i == 6) [iv7 setImage:gemImage];
459 [prefsPanel setFrameAutosaveName:@"prefsPanel"];
460 [prefsPanel makeKeyAndOrderFront:self];
463 - (IBAction)showHighScores
465 // rotate which scores to show
467 gameNames = [hiScores objectAtIndex:gameLevel*2];
468 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
470 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
471 localizedStringForKey:@"EasyHighScoresHTML"
472 value:nil table:nil]];
473 else if (gameLevel==1)
474 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
475 localizedStringForKey:@"HardHighScoresHTML"
476 value:nil table:nil]];
477 else if (gameLevel==2)
478 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
479 localizedStringForKey:@"ToughHighScoresHTML"
480 value:nil table:nil]];
481 else if (gameLevel==3)
482 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
483 localizedStringForKey:@"FreePlayHighScoresHTML"
484 value:nil table:nil]];
485 gameLevel = (gameLevel +1)%4;
487 [gameView showHighScores:gameScores andNames:gameNames];
488 [gameView setLastMoveDate]; //reset timer so scores show for 20s
491 - (IBAction)resetHighScores
493 // don't rotate which scores to show
495 // blank the hi scores
498 hiScores = [[self makeBlankHiScoresWith:nil] retain];
499 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
501 [self showHighScores]; //call the show scores routine
504 - (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores
508 NSMutableArray *result = [NSMutableArray arrayWithCapacity:0];
510 if (oldScores) result = [NSMutableArray arrayWithArray:oldScores];
512 //for (i = 0; i < 3; i++)
513 while ([result count] < 8)
515 NSMutableArray *scores = [NSMutableArray arrayWithCapacity:0];
516 NSMutableArray *names = [NSMutableArray arrayWithCapacity:0];
517 for (j = 0; j < 10; j++)
519 [scores addObject:[NSNumber numberWithInt:1000]];
520 [names addObject:[[NSBundle mainBundle]
521 localizedStringForKey:@"AnonymousName"
522 value:nil table:nil]];
524 [result addObject:names];
525 [result addObject:scores];
527 return [NSArray arrayWithArray:result];
532 _gameState = GAMESTATE_GAMEOVER;
533 [abortGameButton setEnabled:NO];
534 [pauseGameButton setEnabled:NO];
536 [gameView setHTMLLegend:gameOverString];
538 [self startAnimation:@selector(waitForFirstClick)];
541 - (void)checkHiScores
544 // reset arrays with gameLevel
545 gameNames = [hiScores objectAtIndex:gameLevel*2];
546 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
547 for (i = 0; i < 10; i++)
549 if (game.score > [[gameScores objectAtIndex:i] intValue])
551 [hiScorePanelScoreTextField
552 setStringValue:[NSString stringWithFormat:@"%d", game.score]];
553 [NSApp beginSheet:hiScorePanel
554 modalForWindow:gameWindow
561 [gameView showHighScores:gameScores andNames:gameNames];
567 [gameView newBackground];
569 if (!muted) [[NSSound soundNamed:@"yes"] play];
571 if (!freePlay) { // FREEPLAY MW
572 [game increaseBonusMultiplier];
573 [timerView decrementMeter:0.5];
575 [game increaseBonusMultiplier];
576 [timerView decrementMeter:1];
579 if (gameSpeed < SPEED_LIMIT) // capping speed limit
580 gameSpeed = gameSpeed * 1.5;
581 //NSLog(@"...gamesSpeed %f",gameSpeed);
582 [timerView setTimerRunningEvery:0.5/gameSpeed
583 decrement:(0.5/gameTime)
585 whenRunOut:@selector(runOutOfTime)
586 whenRunOver:@selector(bonusAwarded)];
588 if (freePlay) [timerView setDecrement:0];// FREEPLAY
591 - (void)startAnimation:(SEL)andThenSelector
593 [animationTimerLock lock];
596 timer = [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL
598 selector:@selector(animate)
600 repeats:YES] retain];
602 whatNext = andThenSelector;
604 gameView.animating = YES;
606 [animationTimerLock unlock];
609 - (void)animationEnded
611 //NSLog(@"gameController.animationEnded messaged");
613 [animationTimerLock lock];
615 gameView.animating = NO;
617 [animationTimerLock unlock];
619 if (whatNext) [self performSelector:whatNext];
621 [gameView setNeedsDisplay:YES];
624 - (void)waitForNewGame
626 [self checkHiScores];
628 [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
629 [gameView setLegend:titleImage];
630 [easyGameButton setEnabled:YES];
631 [hardGameButton setEnabled:YES];
632 [toughGameButton setEnabled:YES];
633 [abortGameButton setEnabled:NO];
634 [pauseGameButton setEnabled:NO];
639 //NSLog(@"newBoard1");
641 [self startAnimation:@selector(newBoard2)];
648 //NSLog(@"newBoard2");
649 for (i = 0; i < 8; i++)
651 for (j = 0; j < 8; j++)
653 gem = [game gemAt:i:j];
654 //NSLog(@"..gem..%@",gem);
657 //[gem setImage:[[gameView imageArray] objectAtIndex:r]];
658 [gem setSprite:[[gameView spriteArray] objectAtIndex:r]];
659 [gem setPositionOnBoard:i:j];
660 [gem setPositionOnScreen:i*48:(i+j+8)*48];
664 [gameView newBackground];
665 [gameView setLegend:nil];
666 [self startAnimation:@selector(testForThreesAgain)];
669 - (void)waitForFirstClick
671 //NSLog(@"waitForFirstClick");
672 /*- if (!freePlay) MW CHANGE -*/ [timerView setPaused:NO];
675 [timerView setTimer:0.5];
676 _gameState = GAMESTATE_GAMEOVER;
677 [game explodeGameOver];
678 [self startAnimation:@selector(waitForNewGame)];
681 if (![game boardHasMoves])
683 [timerView setPaused:YES];
684 [gameView setHTMLLegend:noMoreMovesString];
687 if (freePlay) [self startAnimation:@selector(runOutOfTime)];// FREEPLAY
688 else [self startAnimation:@selector(newBoard1)];// FREEPLAY
692 _gameState = GAMESTATE_AWAITINGFIRSTCLICK;
695 - (void)receiveClickAt:(int)x:(int)y
698 if ((x < 0)||(x > 383)||(y < 0)||(y > 383)) return;
699 if (_gameState == GAMESTATE_AWAITINGFIRSTCLICK)
701 chx1 = floor(x / 48);
702 chy1 = floor(y / 48);
703 _gameState = GAMESTATE_AWAITINGSECONDCLICK;
704 [gameView setNeedsDisplay:YES];
707 if (_gameState == GAMESTATE_AWAITINGSECONDCLICK)
709 chx2 = floor(x / 48);
710 chy2 = floor(y / 48);
711 if ((chx2 != chx1)^(chy2 != chy1)) // xor!
713 int d = (chx1-chx2)*(chx1-chx2)+(chy1-chy2)*(chy1-chy2);
714 //NSLog(@"square distance ==%d",d);
717 _gameState = GAMESTATE_FRACULATING;
718 [gameView setNeedsDisplay:YES];
719 [gameView setLastMoveDate];
720 /*- MW CHANGE if (!freePlay) -*/ [timerView setPaused:YES];
721 [self tryMoveSwapping:chx1:chy1 and:chx2:chy2];
725 // fall out of routine setting first click location
726 chx1 = floor(x / 48);
727 chy1 = floor(y / 48);
728 _gameState = GAMESTATE_AWAITINGSECONDCLICK;
729 [gameView setNeedsDisplay:YES];
733 - (void)tryMoveSwapping:(int)x1:(int)y1 and:(int)x2:(int)y2
736 int xx1, yy1, xx2, yy2;
737 //NSLog(@"tryMoveSwapping");
740 if (x1 < x2) { xx1 = x1; xx2 = x2; }
741 else { xx1 = x2; xx2 = x1; }
747 if (y1 < y2) { yy1 = y1; yy2 = y2; }
748 else { yy1 = y2; yy2 = y1; }
752 // store swap positions
753 chx1 = xx1; chy1 = yy1; chx2 = xx2; chy2 = yy2;
755 if (chx1 < chx2) // swapping horizontally
757 [[game gemAt:chx1:chy1] setVelocity:gemMoveSpeed:0:gemMoveSteps];
758 [[game gemAt:chx2:chy2] setVelocity:-gemMoveSpeed:0:gemMoveSteps];
760 else // swapping vertically
762 [[game gemAt:chx1:chy1] setVelocity:0:gemMoveSpeed:gemMoveSteps];
763 [[game gemAt:chx2:chy2] setVelocity:0:-gemMoveSpeed:gemMoveSteps];
765 [game swap:chx1:chy1 and:chx2:chy2];
766 _gameState = GAMESTATE_SWAPPING;
767 [self startAnimation:@selector(testForThrees)];
771 - (void)testForThrees
774 int oldScore = game.score;
775 //NSLog(@"testForThrees");
776 anyThrees = ([game testForThreeAt:chx1:chy1])|([game testForThreeAt:chx2:chy2]);
777 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game.score]];
778 [scoreTextField setNeedsDisplay:YES];
779 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game.bonusMultiplier]];
780 [bonusTextField setNeedsDisplay:YES];
781 if (game.score > oldScore) [timerView incrementMeter:[game collectFadedGems]/GEMS_FOR_BONUS];
783 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
788 //// repeat: remove threes
789 - (void)removeThreesAndReplaceGems
792 //NSLog(@"removeThreesAndReplaceGems");
794 [game removeFadedGemsAndReorganiseWithSpritesFrom:[gameView spriteArray]];
796 [self startAnimation:@selector(testForThreesAgain)]; // gems fall down
799 - (void)testForThreesAgain
801 int oldScore = game.score;
802 BOOL anyThrees = [game checkBoardForThrees];
804 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game.score]];
805 [scoreTextField setNeedsDisplay:YES];
807 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game.bonusMultiplier]];
808 [bonusTextField setNeedsDisplay:YES];
810 if (game.score > oldScore) {
811 [timerView incrementMeter:[game collectFadedGems]/GEMS_FOR_BONUS];
814 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
817 [self waitForFirstClick];
820 //// allow gems to fall
822 //// until there are no threes
828 if (!muted) [[NSSound soundNamed:@"no"] play];
831 if (chx1 < chx2) // swapping horizontally
833 [[game gemAt:chx1:chy1] setVelocity:4:0:12];
834 [[game gemAt:chx2:chy2] setVelocity:-4:0:12];
836 else // swapping vertically
838 [[game gemAt:chx1:chy1] setVelocity:0:4:12];
839 [[game gemAt:chx2:chy2] setVelocity:0:-4:12];
841 [game swap:chx1:chy1 and:chx2:chy2];
842 _gameState = GAMESTATE_SWAPPING;
843 [self startAnimation:@selector(waitForFirstClick)];
846 - (BOOL)gameIsPaused {
850 - (BOOL)useCustomBackgrounds {
851 return useCustomBackgrounds;
854 - (NSPoint)crossHair1Position {
855 return NSMakePoint(chx1 * 48,chy1 * 48);
858 - (NSPoint)crossHair2Position {
859 return NSMakePoint(chx2 * 48,chy2 * 48);