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;
36 hiScores = [[NSUserDefaults standardUserDefaults] arrayForKey:@"hiScores"];
38 //NSLog(@"hiScores : %@",hiScores);
40 if ((!hiScores)||([hiScores count] < 8))
42 //NSLog(@"Creating High Score Tables");
43 hiScores = [self makeBlankHiScoresWith:hiScores];
44 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
48 noMoreMovesString = [[NSBundle mainBundle]
49 localizedStringForKey:@"NoMoreMovesHTML"
51 jeweltoyStartString = [[NSBundle mainBundle]
52 localizedStringForKey:@"JewelToyStartHTML"
54 gameOverString = [[NSBundle mainBundle]
55 localizedStringForKey:@"GameOverHTML"
57 titleImage = [NSImage imageNamed:@"title"];
59 gameNames = [hiScores objectAtIndex:0];
60 gameScores = [hiScores objectAtIndex:1];
62 game = [[Game alloc] init];
63 animationTimerLock = [[NSLock alloc] init];
65 gemMoveSize = GEM_GRAPHIC_SIZE;
66 gemMoveSpeed = GEM_MOVE_SPEED;
67 gemMoveSteps = gemMoveSize / gemMoveSpeed;
69 useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
70 useImportedGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useImportedGraphics"];
72 useCustomBackgrounds = [[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"];
73 customBackgroundFolderPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"];
74 if (!customBackgroundFolderPath)
75 customBackgroundFolderPath = [[NSBundle mainBundle] localizedStringForKey:@"PicturesFolderPath"
82 if (noMoreMovesString) [noMoreMovesString release];
83 if (jeweltoyStartString) [jeweltoyStartString release];
84 if (gameOverString) [gameOverString release];
85 if (game) [game release];
86 if (animationTimerLock) [animationTimerLock release];
87 if (timer) [timer release];
88 if (hiScores) [hiScores release];
94 [gameWindow setFrameAutosaveName:@"gameWindow"];
95 //useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
98 - (void)windowWillClose:(NSNotification *)aNotification
100 id obj = [aNotification object];
101 if (obj == aboutPanel)
103 //NSLog(@"Someone closed the 'About' window");
107 if (obj == prefsPanel)
109 //NSLog(@"Someone closed the 'Preferences' window");
110 useAlternateGraphics = [prefsAlternateGraphicsButton state];
111 [[NSUserDefaults standardUserDefaults] setBool:useAlternateGraphics
112 forKey:@"useAlternateGraphics"];
113 [[NSUserDefaults standardUserDefaults] setBool:useImportedGraphics
114 forKey:@"useImportedGraphics"];
116 useCustomBackgrounds = [prefsCustomBackgroundCheckbox state];
117 [[NSUserDefaults standardUserDefaults] setBool:useCustomBackgrounds
118 forKey:@"useCustomBackgrounds"];
119 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"customBackgroundFolderPath"];
120 [[NSUserDefaults standardUserDefaults] setObject:[prefsCustomBackgroundFolderTextField stringValue]
121 forKey:@"customBackgroundFolderPath"];
124 //[gameView loadImageArray];
125 [gameView graphicSetUp];
126 [gameView newBackground];
127 if (game) [game setSpritesFrom:[gameView spriteArray]];
128 [gameView setNeedsDisplay:YES];
133 if (obj == gameWindow)
135 //NSLog(@"Someone closed the window - shutting down JewelToy");
136 [NSApp terminate:self];
141 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
142 [prefsCustomBackgroundFolderTextField setStringValue:[[sheet filenames] objectAtIndex:0]];
145 // TODO: move algorithm to its own method
146 - (IBAction)prefsGraphicDropAction:(id)sender
149 // slice and dice importedImage, saving images to defaults
151 NSImage *importedImage = [prefsAlternateGraphicsImageView image];
155 NSRect cropRect = NSMakeRect(0.0,0.0,[importedImage size].width/7.0,[importedImage size].height);
156 NSRect gemRect = NSMakeRect(0.0,0.0,48.0,48.0);
157 NSSize imageSize = NSMakeSize(48.0,48.0);
158 for (i = 0; i < 7; i++)
160 NSImage *gemImage = [[NSImage alloc] initWithSize:imageSize];
161 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
162 cropRect.origin.x = i * [importedImage size].width/7.0;
163 [gemImage lockFocus];
164 [[NSColor clearColor] set];
166 [importedImage drawInRect:gemRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0];
167 [gemImage unlockFocus];
168 [[NSUserDefaults standardUserDefaults] setObject:[gemImage TIFFRepresentation] forKey:key];
169 if (i == 0) [iv1 setImage:gemImage];
170 if (i == 1) [iv2 setImage:gemImage];
171 if (i == 2) [iv3 setImage:gemImage];
172 if (i == 3) [iv4 setImage:gemImage];
173 if (i == 4) [iv5 setImage:gemImage];
174 if (i == 5) [iv6 setImage:gemImage];
175 if (i == 6) [iv7 setImage:gemImage];
178 useImportedGraphics = YES;
183 - (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender
185 //NSLog(@"prefsCustomBackgroundCheckboxAction");
187 if (sender!=prefsCustomBackgroundCheckbox)
189 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
190 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
194 - (IBAction)prefsSelectFolderButtonAction:(id)sender
196 NSOpenPanel *op=[NSOpenPanel openPanel];
198 //NSLog(@"prefsSelectFolderButtonAction");
199 [op setCanChooseDirectories:YES];
200 [op setCanChooseFiles:NO];
201 // get a sheet going to let the user pick a folder to scan for pictures
202 [op beginSheetForDirectory:[prefsCustomBackgroundFolderTextField stringValue] file:NULL types:NULL modalForWindow:prefsPanel modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
205 - (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem
207 if (aMenuItem == easyGameMenuItem)
208 return [easyGameButton isEnabled];
209 if (aMenuItem == hardGameMenuItem)
210 return [hardGameButton isEnabled];
211 if (aMenuItem == toughGameMenuItem)
212 return [toughGameButton isEnabled];
213 if (aMenuItem == freePlayMenuItem)
214 return [easyGameButton isEnabled];
215 if (aMenuItem == abortGameMenuItem)
216 return [abortGameButton isEnabled];
217 if (aMenuItem == pauseGameMenuItem)
218 return [pauseGameButton isEnabled];
220 // only allow viewing and reset of scores between games
222 if (aMenuItem == showHighScoresMenuItem)
223 return [easyGameButton isEnabled];
224 if (aMenuItem == resetHighScoresMenuItem)
225 return [easyGameButton isEnabled];
229 - (IBAction)startNewGame:(id)sender
231 //NSLog(@"gameController.startNewGame messaged gameView:%@",gameView);
233 [easyGameButton setEnabled:NO];
234 [hardGameButton setEnabled:NO];
235 [toughGameButton setEnabled:NO];
236 [abortGameButton setEnabled:YES];
237 [pauseGameButton setEnabled:YES];
243 if ((sender == easyGameButton) ||
244 (sender == easyGameMenuItem)) {
245 //NSLog(@"debug - hiScores = %@\n...hiScores.count = %d",hiScores,[hiScores count]);
247 gameTime = 600.0; // ten minutes
248 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
249 localizedStringForKey:@"EasyHighScoresHTML"
250 value:nil table:nil]];
252 // TODO: add else if?
253 if ((sender == hardGameButton) ||
254 (sender == hardGameMenuItem)) {
256 gameTime = 180.0; // three minutes
257 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
258 localizedStringForKey:@"HardHighScoresHTML"
259 value:nil table:nil]];
261 // TODO: add else if?
262 if ((sender == toughGameButton) ||
263 (sender == toughGameMenuItem)) {
265 gameTime = 90.0; // one and a half minutes
266 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
267 localizedStringForKey:@"ToughHighScoresHTML"
268 value:nil table:nil]];
271 if (sender==freePlayMenuItem)
274 gameTime = 3600.0; // one hour FWIW
275 freePlay = YES;// FREEPLAY
276 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
277 localizedStringForKey:@"FreePlayHighScoresHTML"
278 value:nil table:nil]];
281 freePlay = NO;// FREEPLAY
284 gameNames = [hiScores objectAtIndex:gameLevel*2];
285 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
286 [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
288 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game._score]];
289 [scoreTextField setNeedsDisplay:YES];
290 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game._bonusMultiplier]];
291 [bonusTextField setNeedsDisplay:YES];
293 [game setMuted:muted];
294 [gameView setGame:game];
295 [gameView setLegend:nil];
296 [gameView setPaused:NO];
297 [gameView setMuted:muted];
298 [gameView setShowHint:!freePlay];// FREEPLAY
300 [timerView setTimerRunningEvery:0.5/gameSpeed
301 decrement:(0.5/gameTime)
303 whenRunOut:@selector(runOutOfTime)
304 whenRunOver:@selector(bonusAwarded)];
308 [timerView setDecrement:0.0];// FREEPLAY MW
309 [timerView setTimer:0.0];
312 [timerView setPaused:YES];
314 [gameView setLastMoveDate];
315 [self startAnimation:@selector(waitForFirstClick)];
318 - (IBAction)abortGame:(id)sender
320 [abortGameButton setEnabled:NO];
321 if (paused) [self togglePauseMode:self];
322 [pauseGameButton setEnabled:NO];
324 [self waitForFirstClick];
327 - (IBAction)receiveHiScoreName:(id)sender
330 int score = [hiScorePanelScoreTextField intValue];
331 NSString *name = [hiScorePanelNameTextField stringValue];
333 [NSApp endSheet:hiScorePanel];
334 [hiScorePanel close];
336 //NSLog(@"receiving HiScoreName:%@ %d",name,score);
338 // reset arrays to gameLevel
339 gameNames = [hiScores objectAtIndex:gameLevel*2];
340 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
342 for (i = 0; i < 10; i++)
344 if (score > [[gameScores objectAtIndex:i] intValue])
346 [gameScores insertObject:[NSNumber numberWithInt:score] atIndex:i];
347 [gameScores removeObjectAtIndex:10];
348 [gameNames insertObject:name atIndex:i];
349 [gameNames removeObjectAtIndex:10];
354 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hiScores"]; // or it won't work!?!
355 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
357 //NSLog(@"written high-scores to preferences");
359 _gameState = GAMESTATE_GAMEOVER;
360 [gameView showHighScores:gameScores andNames:gameNames];
361 [gameView setLastMoveDate]; //reset timer so scores show for 20s
364 - (IBAction)togglePauseMode:(id)sender
366 //NSLog(@"Pause game toggled, sender state is %d",[sender state]);
367 if (sender == pauseGameButton)
368 paused = [sender state];
372 [pauseGameButton setState:paused];
373 [timerView setPaused:paused];
376 [gameView setPaused:YES];
377 [gameView setHTMLLegend:[[NSBundle mainBundle]
378 localizedStringForKey:@"PausedHTML"
379 value:nil table:nil]];
380 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
381 localizedStringForKey:@"ContinueGameMenuItemTitle"
382 value:nil table:nil]];
386 [gameView setPaused:NO];
387 [gameView setLegend:nil];
388 [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
389 localizedStringForKey:@"PauseGameMenuItemTitle"
390 value:nil table:nil]];
394 - (IBAction)toggleMute:(id)sender
396 if (sender == muteButton)
397 muted = [sender state];
401 [muteButton setState:muted];
402 [gameView setMuted:muted];
403 [game setMuted:muted];
406 [muteMenuItem setTitle:[[NSBundle mainBundle]
407 localizedStringForKey:@"UnMuteGameMenuItemTitle"
408 value:nil table:nil]];
410 [muteMenuItem setTitle:[[NSBundle mainBundle]
411 localizedStringForKey:@"MuteGameMenuItemTitle"
412 value:nil table:nil]];
416 - (IBAction)orderFrontAboutPanel:(id)sender
418 //NSLog(@"GameController showAboutPanel called");
420 [NSBundle loadNibNamed:@"About" owner:self];
421 [aboutPanel setFrameAutosaveName:@"aboutPanel"];
422 [aboutPanel makeKeyAndOrderFront:self];
425 - (IBAction)orderFrontPreferencesPanel:(id)sender
428 [NSBundle loadNibNamed:@"Preferences" owner:self];
430 [prefsStandardGraphicsButton setState:!useAlternateGraphics];
431 [prefsAlternateGraphicsButton setState:useAlternateGraphics];
433 [prefsCustomBackgroundCheckbox setState:useCustomBackgrounds];
434 [prefsCustomBackgroundFolderTextField setStringValue:customBackgroundFolderPath];
435 [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
436 [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
438 if ([[NSUserDefaults standardUserDefaults] dataForKey:@"tiffGemImage0"])
441 for (i = 0; i < 7; i++)
443 NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
444 NSData *tiffData = [[NSUserDefaults standardUserDefaults] dataForKey:key];
445 NSImage *gemImage = [[NSImage alloc] initWithData:tiffData];
446 if (i == 0) [iv1 setImage:gemImage];
447 if (i == 1) [iv2 setImage:gemImage];
448 if (i == 2) [iv3 setImage:gemImage];
449 if (i == 3) [iv4 setImage:gemImage];
450 if (i == 4) [iv5 setImage:gemImage];
451 if (i == 5) [iv6 setImage:gemImage];
452 if (i == 6) [iv7 setImage:gemImage];
457 [prefsPanel setFrameAutosaveName:@"prefsPanel"];
458 [prefsPanel makeKeyAndOrderFront:self];
461 - (IBAction)showHighScores:(id)sender
463 // rotate which scores to show
465 gameNames = [hiScores objectAtIndex:gameLevel*2];
466 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
468 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
469 localizedStringForKey:@"EasyHighScoresHTML"
470 value:nil table:nil]];
471 else if (gameLevel==1)
472 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
473 localizedStringForKey:@"HardHighScoresHTML"
474 value:nil table:nil]];
475 else if (gameLevel==2)
476 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
477 localizedStringForKey:@"ToughHighScoresHTML"
478 value:nil table:nil]];
479 else if (gameLevel==3)
480 [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
481 localizedStringForKey:@"FreePlayHighScoresHTML"
482 value:nil table:nil]];
483 gameLevel = (gameLevel +1)%4;
485 [gameView showHighScores:gameScores andNames:gameNames];
486 [gameView setLastMoveDate]; //reset timer so scores show for 20s
489 - (IBAction)resetHighScores:(id)sender
491 // don't rotate which scores to show
493 // blank the hi scores
496 hiScores = [[self makeBlankHiScoresWith:nil] retain];
497 [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
499 [self showHighScores:sender]; //call the show scores routine
502 - (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores
506 NSMutableArray *result = [NSMutableArray arrayWithCapacity:0];
508 if (oldScores) result = [NSMutableArray arrayWithArray:oldScores];
510 //for (i = 0; i < 3; i++)
511 while ([result count] < 8)
513 NSMutableArray *scores = [NSMutableArray arrayWithCapacity:0];
514 NSMutableArray *names = [NSMutableArray arrayWithCapacity:0];
515 for (j = 0; j < 10; j++)
517 [scores addObject:[NSNumber numberWithInt:1000]];
518 [names addObject:[[NSBundle mainBundle]
519 localizedStringForKey:@"AnonymousName"
520 value:nil table:nil]];
522 [result addObject:names];
523 [result addObject:scores];
525 return [NSArray arrayWithArray:result];
530 _gameState = GAMESTATE_GAMEOVER;
531 [abortGameButton setEnabled:NO];
532 [pauseGameButton setEnabled:NO];
534 [gameView setHTMLLegend:gameOverString];
536 [self startAnimation:@selector(waitForFirstClick)];
539 - (void)checkHiScores
542 // reset arrays with gameLevel
543 gameNames = [hiScores objectAtIndex:gameLevel*2];
544 gameScores = [hiScores objectAtIndex:gameLevel*2+1];
545 for (i = 0; i < 10; i++)
547 if (game._score > [[gameScores objectAtIndex:i] intValue])
549 [hiScorePanelScoreTextField
550 setStringValue:[NSString stringWithFormat:@"%d", game._score]];
551 [NSApp beginSheet:hiScorePanel
552 modalForWindow:gameWindow
559 [gameView showHighScores:gameScores andNames:gameNames];
565 [gameView newBackground];
567 if (!muted) [[NSSound soundNamed:@"yes"] play];
569 if (!freePlay) { // FREEPLAY MW
570 [game increaseBonusMultiplier];
571 [timerView decrementMeter:0.5];
573 [game increaseBonusMultiplier];
574 [timerView decrementMeter:1];
577 if (gameSpeed < SPEED_LIMIT) // capping speed limit
578 gameSpeed = gameSpeed * 1.5;
579 //NSLog(@"...gamesSpeed %f",gameSpeed);
580 [timerView setTimerRunningEvery:0.5/gameSpeed
581 decrement:(0.5/gameTime)
583 whenRunOut:@selector(runOutOfTime)
584 whenRunOver:@selector(bonusAwarded)];
586 if (freePlay) [timerView setDecrement:0];// FREEPLAY
589 - (void)startAnimation:(SEL)andThenSelector
591 [animationTimerLock lock];
594 timer = [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL
596 selector:@selector(animate)
598 repeats:YES] retain];
600 whatNext = andThenSelector;
602 gameView._animating = YES;
604 [animationTimerLock unlock];
607 - (void)animationEnded
609 //NSLog(@"gameController.animationEnded messaged");
611 [animationTimerLock lock];
613 gameView._animating = NO;
615 [animationTimerLock unlock];
617 if (whatNext) [self performSelector:whatNext];
619 [gameView setNeedsDisplay:YES];
622 - (void)waitForNewGame
624 [self checkHiScores];
626 [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
627 [gameView setLegend:titleImage];
628 [easyGameButton setEnabled:YES];
629 [hardGameButton setEnabled:YES];
630 [toughGameButton setEnabled:YES];
631 [abortGameButton setEnabled:NO];
632 [pauseGameButton setEnabled:NO];
637 //NSLog(@"newBoard1");
639 [self startAnimation:@selector(newBoard2)];
646 //NSLog(@"newBoard2");
647 for (i = 0; i < 8; i++)
649 for (j = 0; j < 8; j++)
651 gem = [game gemAt:i:j];
652 //NSLog(@"..gem..%@",gem);
655 //[gem setImage:[[gameView imageArray] objectAtIndex:r]];
656 [gem setSprite:[[gameView spriteArray] objectAtIndex:r]];
657 [gem setPositionOnBoard:i:j];
658 [gem setPositionOnScreen:i*48:(i+j+8)*48];
662 [gameView newBackground];
663 [gameView setLegend:nil];
664 [self startAnimation:@selector(testForThreesAgain)];
667 - (void)waitForFirstClick
669 //NSLog(@"waitForFirstClick");
670 /*- if (!freePlay) MW CHANGE -*/ [timerView setPaused:NO];
673 [timerView setTimer:0.5];
674 _gameState = GAMESTATE_GAMEOVER;
675 [game explodeGameOver];
676 [self startAnimation:@selector(waitForNewGame)];
679 if (![game boardHasMoves])
681 [timerView setPaused:YES];
682 [gameView setHTMLLegend:noMoreMovesString];
685 if (freePlay) [self startAnimation:@selector(runOutOfTime)];// FREEPLAY
686 else [self startAnimation:@selector(newBoard1)];// FREEPLAY
690 _gameState = GAMESTATE_AWAITINGFIRSTCLICK;
693 - (void)receiveClickAt:(int)x:(int)y
696 if ((x < 0)||(x > 383)||(y < 0)||(y > 383)) return;
697 if (_gameState == GAMESTATE_AWAITINGFIRSTCLICK)
699 chx1 = floor(x / 48);
700 chy1 = floor(y / 48);
701 _gameState = GAMESTATE_AWAITINGSECONDCLICK;
702 [gameView setNeedsDisplay:YES];
705 if (_gameState == GAMESTATE_AWAITINGSECONDCLICK)
707 chx2 = floor(x / 48);
708 chy2 = floor(y / 48);
709 if ((chx2 != chx1)^(chy2 != chy1)) // xor!
711 int d = (chx1-chx2)*(chx1-chx2)+(chy1-chy2)*(chy1-chy2);
712 //NSLog(@"square distance ==%d",d);
715 _gameState = GAMESTATE_FRACULATING;
716 [gameView setNeedsDisplay:YES];
717 [gameView setLastMoveDate];
718 /*- MW CHANGE if (!freePlay) -*/ [timerView setPaused:YES];
719 [self tryMoveSwapping:chx1:chy1 and:chx2:chy2];
723 // fall out of routine setting first click location
724 chx1 = floor(x / 48);
725 chy1 = floor(y / 48);
726 _gameState = GAMESTATE_AWAITINGSECONDCLICK;
727 [gameView setNeedsDisplay:YES];
731 - (void)tryMoveSwapping:(int)x1:(int)y1 and:(int)x2:(int)y2
734 int xx1, yy1, xx2, yy2;
735 //NSLog(@"tryMoveSwapping");
738 if (x1 < x2) { xx1 = x1; xx2 = x2; }
739 else { xx1 = x2; xx2 = x1; }
745 if (y1 < y2) { yy1 = y1; yy2 = y2; }
746 else { yy1 = y2; yy2 = y1; }
750 // store swap positions
751 chx1 = xx1; chy1 = yy1; chx2 = xx2; chy2 = yy2;
753 if (chx1 < chx2) // swapping horizontally
755 [[game gemAt:chx1:chy1] setVelocity:gemMoveSpeed:0:gemMoveSteps];
756 [[game gemAt:chx2:chy2] setVelocity:-gemMoveSpeed:0:gemMoveSteps];
758 else // swapping vertically
760 [[game gemAt:chx1:chy1] setVelocity:0:gemMoveSpeed:gemMoveSteps];
761 [[game gemAt:chx2:chy2] setVelocity:0:-gemMoveSpeed:gemMoveSteps];
763 [game swap:chx1:chy1 and:chx2:chy2];
764 _gameState = GAMESTATE_SWAPPING;
765 [self startAnimation:@selector(testForThrees)];
769 - (void)testForThrees
772 int oldScore = game._score;
773 //NSLog(@"testForThrees");
774 anyThrees = ([game testForThreeAt:chx1:chy1])|([game testForThreeAt:chx2:chy2]);
775 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game._score]];
776 [scoreTextField setNeedsDisplay:YES];
777 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game._bonusMultiplier]];
778 [bonusTextField setNeedsDisplay:YES];
779 if (game._score > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS];
781 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
786 //// repeat: remove threes
787 - (void)removeThreesAndReplaceGems
790 //NSLog(@"removeThreesAndReplaceGems");
792 [game removeFadedGemsAndReorganiseWithSpritesFrom:[gameView spriteArray]];
794 [self startAnimation:@selector(testForThreesAgain)]; // gems fall down
797 - (void)testForThreesAgain
800 int oldScore = game._score;
801 //NSLog(@"testForThreesAgain");
802 anyThrees = [game checkBoardForThrees];
803 [scoreTextField setStringValue:[NSString stringWithFormat:@"%d", game._score]];
804 [scoreTextField setNeedsDisplay:YES];
805 [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d", game._bonusMultiplier]];
806 [bonusTextField setNeedsDisplay:YES];
807 if (game._score > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS];
809 [self startAnimation:@selector(removeThreesAndReplaceGems)]; // fade gems
811 [self waitForFirstClick];
813 //// allow gems to fall
815 //// until there are no threes
821 if (!muted) [[NSSound soundNamed:@"no"] play];
824 if (chx1 < chx2) // swapping horizontally
826 [[game gemAt:chx1:chy1] setVelocity:4:0:12];
827 [[game gemAt:chx2:chy2] setVelocity:-4:0:12];
829 else // swapping vertically
831 [[game gemAt:chx1:chy1] setVelocity:0:4:12];
832 [[game gemAt:chx2:chy2] setVelocity:0:-4:12];
834 [game swap:chx1:chy1 and:chx2:chy2];
835 _gameState = GAMESTATE_SWAPPING;
836 [self startAnimation:@selector(waitForFirstClick)];
839 - (BOOL) gameIsPaused {
843 - (BOOL) useCustomBackgrounds {
844 return useCustomBackgrounds;
847 - (NSPoint) crossHair1Position {
848 return NSMakePoint(chx1*48,chy1*48);
851 - (NSPoint) crossHair2Position
853 return NSMakePoint(chx2*48,chy2*48);