cleaning
[exterlulz-kokomonds.git] / src / GameController.m
blob5fe1e8cde4b37107c91bd55715351827837ee020
1 /* ----====----====----====----====----====----====----====----====----====----
2  GameController.m (jeweltoy)
3  
4  JewelToy is a simple game played against the clock.
5  Copyright (C) 2001  Giles Williams
6  
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 /* kokomonds is a fork of JewelToy.
23  * repository: http://github.com/exterlulz/kokomonds
24  */
26 // TODO: clean
28 #import "GameController.h"
29 #import "TimerView.h"
30 #import "Game.h"
31 #import "GameView.h"
32 #import "Gem.h"
34 @implementation GameController
36 - (id)init
38   self = [super init];
39   if (self != nil) {
40     hiScores = [[NSUserDefaults standardUserDefaults] arrayForKey:@"hiScores"];
41     
42     //NSLog(@"hiScores : %@",hiScores);
43     
44     if ((!hiScores)||([hiScores count] < 8))
45     {
46       //NSLog(@"Creating High Score Tables");
47       hiScores = [self makeBlankHiScoresWith:hiScores];
48       [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
49     }
50     [hiScores retain];
51     
52     noMoreMovesString = [[NSBundle mainBundle]
53                          localizedStringForKey:@"NoMoreMovesHTML"
54                          value:nil table:nil];
55     jeweltoyStartString = [[NSBundle mainBundle]
56                            localizedStringForKey:@"JewelToyStartHTML"
57                            value:nil table:nil];
58     gameOverString = [[NSBundle mainBundle]
59                       localizedStringForKey:@"GameOverHTML"
60                       value:nil table:nil];
61     titleImage = [NSImage imageNamed:@"title"];
62     gameLevel = 0;
63     gameNames = [hiScores objectAtIndex:0];
64     gameScores = [hiScores objectAtIndex:1];
65     
66     game = [[Game alloc] init];
67     animationTimerLock = [[NSLock alloc] init];
68     
69     gemMoveSize = GEM_GRAPHIC_SIZE;
70     gemMoveSpeed = GEM_MOVE_SPEED;
71     gemMoveSteps = gemMoveSize / gemMoveSpeed;
72     
73     useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
74     useImportedGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useImportedGraphics"];
75     
76     useCustomBackgrounds = [[NSUserDefaults standardUserDefaults] boolForKey:@"useCustomBackgrounds"];
77     customBackgroundFolderPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"customBackgroundFolderPath"];
78     if (!customBackgroundFolderPath)
79       customBackgroundFolderPath = [[NSBundle mainBundle] localizedStringForKey:@"PicturesFolderPath"
80                                                                           value:nil table:nil];
81   }
82   
83   return self;
86 - (void) dealloc
88   [noMoreMovesString release];
89   noMoreMovesString = nil;
90   
91   [jeweltoyStartString release];
92   jeweltoyStartString = nil;
93   
94   [gameOverString release];
95   gameOverString = nil;
96   
97   [game release];
98   game = nil;
99   
100   [animationTimerLock release];
101   animationTimerLock = nil;
102   
103   [timer release];
104   timer = nil;
105   
106   [hiScores release];
107   hiScores = nil;
108   
109   [super dealloc];
112 - (void)awakeFromNib
114   [gameWindow setFrameAutosaveName:@"gameWindow"];
115   //useAlternateGraphics = [[NSUserDefaults standardUserDefaults] boolForKey:@"useAlternateGraphics"];
118 - (void)windowWillClose:(NSNotification *)aNotification
120   id obj = [aNotification object];
121   if (obj == aboutPanel)
122   {
123     //NSLog(@"Someone closed the 'About' window");
124     aboutPanel = nil;
125     return;
126   }
127   if (obj == prefsPanel)
128   {
129     //NSLog(@"Someone closed the 'Preferences' window");
130     useAlternateGraphics = [prefsAlternateGraphicsButton state];
131     [[NSUserDefaults standardUserDefaults]      setBool:useAlternateGraphics
132                                             forKey:@"useAlternateGraphics"];
133     [[NSUserDefaults standardUserDefaults]      setBool:useImportedGraphics
134                                             forKey:@"useImportedGraphics"];
135     
136     useCustomBackgrounds = [prefsCustomBackgroundCheckbox state];
137     [[NSUserDefaults standardUserDefaults]      setBool:useCustomBackgrounds
138                                             forKey:@"useCustomBackgrounds"];
139     [[NSUserDefaults standardUserDefaults]      removeObjectForKey:@"customBackgroundFolderPath"];
140     [[NSUserDefaults standardUserDefaults]      setObject:[prefsCustomBackgroundFolderTextField stringValue]
141                                               forKey:@"customBackgroundFolderPath"];
142     if (gameView)
143     {
144       //[gameView loadImageArray];
145       [gameView graphicSetUp];
146       [gameView newBackground];
147       if (game) [game setSpritesFrom:[gameView spriteArray]];
148       [gameView setNeedsDisplay:YES];
149     }
150     prefsPanel = nil;
151     return;
152   }
153   if (obj == gameWindow)
154   {
155     //NSLog(@"Someone closed the window - shutting down JewelToy");
156     [NSApp terminate:self];
157     return;
158   }
161 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void  *)contextInfo
163   #pragma unused (returnCode, contextInfo)
164   [prefsCustomBackgroundFolderTextField setStringValue:[[sheet filenames] objectAtIndex:0]];
167 - (IBAction)prefsGraphicDropAction:(id)sender
169   #pragma unused (sender)
170   
171   //    slice and dice importedImage, saving images to defaults
172   NSImage *importedImage = [prefsAlternateGraphicsImageView image];
173   if (importedImage)
174   {
175     int i = 0;
176     NSRect      cropRect = NSMakeRect(0.0,0.0,[importedImage size].width/7.0,[importedImage size].height);
177     NSRect      gemRect = NSMakeRect(0.0,0.0,48.0,48.0);
178     NSSize imageSize = NSMakeSize(48.0,48.0);
179     for (i = 0; i < 7; i++)
180     {
181       NSImage   *gemImage = [[NSImage alloc] initWithSize:imageSize];
182       NSString *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
183       cropRect.origin.x = i * [importedImage size].width/7.0;
184       [gemImage lockFocus];
185       [[NSColor clearColor] set];
186       NSRectFill(gemRect);
187       [importedImage drawInRect:gemRect fromRect:cropRect operation:NSCompositeSourceOver fraction:1.0];
188       [gemImage unlockFocus];
189       [[NSUserDefaults standardUserDefaults]    setObject:[gemImage TIFFRepresentation] forKey:key];
190       if (i == 0)       [iv1 setImage:gemImage];
191       if (i == 1)       [iv2 setImage:gemImage];
192       if (i == 2)       [iv3 setImage:gemImage];
193       if (i == 3)       [iv4 setImage:gemImage];
194       if (i == 4)       [iv5 setImage:gemImage];
195       if (i == 5)       [iv6 setImage:gemImage];
196       if (i == 6)       [iv7 setImage:gemImage];
197       [gemImage release];
198     }
199     useImportedGraphics = YES;
200   }
201   
204 - (IBAction)prefsCustomBackgroundCheckboxAction:(id)sender
206   //NSLog(@"prefsCustomBackgroundCheckboxAction");
207   
208   if (sender!=prefsCustomBackgroundCheckbox)
209     return;
210   [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
211   [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
212   
215 - (IBAction)prefsSelectFolderButtonAction:(id)sender
217   #pragma unused (sender)
218   
219   NSOpenPanel *op=[NSOpenPanel openPanel];
220   
221   //NSLog(@"prefsSelectFolderButtonAction");
222   [op setCanChooseDirectories:YES];
223   [op setCanChooseFiles:NO];
224   // get a sheet going to let the user pick a folder to scan for pictures
225   [op beginSheetForDirectory:[prefsCustomBackgroundFolderTextField stringValue] file:NULL types:NULL modalForWindow:prefsPanel modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
229 - (BOOL) validateMenuItem: (NSMenuItem*) aMenuItem
231   if (aMenuItem == easyGameMenuItem)
232     return [easyGameButton isEnabled];
233   if (aMenuItem == hardGameMenuItem)
234     return [hardGameButton isEnabled];
235   if (aMenuItem == toughGameMenuItem)
236     return [toughGameButton isEnabled];
237   if (aMenuItem == freePlayMenuItem)
238     return [easyGameButton isEnabled];
239   if (aMenuItem == abortGameMenuItem)
240     return [abortGameButton isEnabled];
241   if (aMenuItem == pauseGameMenuItem)
242     return [pauseGameButton isEnabled];
243   //
244   // only allow viewing and reset of scores between games
245   //
246   if (aMenuItem == showHighScoresMenuItem)
247     return [easyGameButton isEnabled];
248   if (aMenuItem == resetHighScoresMenuItem)
249     return [easyGameButton isEnabled];
250   return YES;
253 - (IBAction)startNewGame:(id)sender
255   //NSLog(@"gameController.startNewGame messaged gameView:%@",gameView);
256   
257   [easyGameButton setEnabled:NO];
258   [hardGameButton setEnabled:NO];
259   [toughGameButton setEnabled:NO];
260   [abortGameButton setEnabled:YES];
261   [pauseGameButton setEnabled:YES];
262   
263   abortGame = NO;
264   gameSpeed = 1.0;
265   gameLevel = 0;
266   
267   if ((sender==easyGameButton)||(sender==easyGameMenuItem))
268   {
269     //NSLog(@"debug - hiScores = %@\n...hiScores.count = %d",hiScores,[hiScores count]);
270     gameLevel = 0;
271     gameTime = 600.0; // ten minutes
272     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
273                                     localizedStringForKey:@"EasyHighScoresHTML"
274                                     value:nil table:nil]];
275   }
276   if ((sender==hardGameButton)||(sender==hardGameMenuItem))
277   {
278     gameLevel = 1;
279     gameTime = 180.0; // three minutes
280     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
281                                     localizedStringForKey:@"HardHighScoresHTML"
282                                     value:nil table:nil]];
283     
284   }
285   if ((sender==toughGameButton)||(sender==toughGameMenuItem))
286   {
287     gameLevel = 2;
288     gameTime = 90.0; // one and a half minutes
289     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
290                                     localizedStringForKey:@"ToughHighScoresHTML"
291                                     value:nil table:nil]];
292   }
293   if (sender==freePlayMenuItem)
294   {
295     gameLevel = 3;
296     gameTime = 3600.0; // one hour FWIW
297     freePlay = YES;//   FREEPLAY
298     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
299                                     localizedStringForKey:@"FreePlayHighScoresHTML"
300                                     value:nil table:nil]];
301   }
302   else
303     freePlay = NO;//    FREEPLAY
304   gameNames = [hiScores objectAtIndex:gameLevel*2];
305   gameScores = [hiScores objectAtIndex:gameLevel*2+1];
306   [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
307   
308   //
309   [scoreTextField setStringValue:[NSString stringWithFormat:@"%d",[game score]]];
310   [scoreTextField setNeedsDisplay:YES];
311   [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d",[game bonusMultiplier]]];
312   [bonusTextField setNeedsDisplay:YES];
313   //
314   
315   [game setMuted:muted];
316   [gameView setGame:game];
317   [gameView setLegend:nil];
318   [gameView setPaused:NO];
319   [gameView setMuted:muted];
320   [gameView setShowHint:!freePlay];//           FREEPLAY
321   
322   [timerView setTimerRunningEvery:0.5/gameSpeed
323                         decrement:(0.5/gameTime)
324                        withTarget:self
325                        whenRunOut:@selector(runOutOfTime)
326                       whenRunOver:@selector(bonusAwarded)];
327   
328   if (freePlay)
329   {
330     [timerView setDecrement:0.0];//     FREEPLAY MW
331     [timerView setTimer:0.0];
332   }
333   
334   [timerView setPaused:YES];
335   
336   [gameView setLastMoveDate];
337   [self startAnimation:@selector(waitForFirstClick)];
340 - (IBAction)abortGame:(id)sender
342   #pragma unused (sender)
343   
344   [abortGameButton setEnabled:NO];
345   if (paused) [self togglePauseMode:self];
346   [pauseGameButton setEnabled:NO];
347   abortGame = YES;
348   [self waitForFirstClick];
350 - (IBAction)receiveHiScoreName:(id)sender
352   #pragma unused (sender)
353   
354   int           i;
355   int           score = [hiScorePanelScoreTextField intValue];
356   NSString      *name = [hiScorePanelNameTextField stringValue];
357   
358   [NSApp endSheet:hiScorePanel];
359   [hiScorePanel close];
360   
361   //NSLog(@"receiving HiScoreName:%@ %d",name,score);
362   
363   // reset arrays to gameLevel    
364   gameNames = [hiScores objectAtIndex:gameLevel*2];
365   gameScores = [hiScores objectAtIndex:gameLevel*2+1];
366   
367   for (i = 0; i < 10; i++)
368   {
369     if (score > [[gameScores objectAtIndex:i] intValue])
370     {
371       [gameScores       insertObject:[NSNumber numberWithInt:score] atIndex:i];
372       [gameScores       removeObjectAtIndex:10];
373       [gameNames        insertObject:name atIndex:i];
374       [gameNames        removeObjectAtIndex:10];
375       break;
376     }
377   }
378   
379   [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hiScores"];       // or it won't work!?!
380   [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
381   
382   //NSLog(@"written high-scores to preferences");
383   
384   gameState = GAMESTATE_GAMEOVER;
385   [gameView showHighScores:gameScores andNames:gameNames];
386   [gameView setLastMoveDate];   //reset timer so scores show for 20s    
389 - (IBAction)togglePauseMode:(id)sender
391   //NSLog(@"Pause game toggled, sender state is %d",[sender state]);
392   if (sender == pauseGameButton)
393     paused = [pauseGameButton state];
394   else
395     paused = !paused;
396   
397   [pauseGameButton setState:paused];
398   [timerView setPaused:paused];
399   if (paused)
400   {
401     [gameView setPaused:YES];
402     [gameView setHTMLLegend:[[NSBundle mainBundle]
403                              localizedStringForKey:@"PausedHTML"
404                              value:nil table:nil]];
405     [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
406                                  localizedStringForKey:@"ContinueGameMenuItemTitle"
407                                  value:nil table:nil]];
408   }
409   else
410   {
411     [gameView setPaused:NO];
412     [gameView setLegend:nil];
413     [pauseGameMenuItem setTitle:[[NSBundle mainBundle]
414                                  localizedStringForKey:@"PauseGameMenuItemTitle"
415                                  value:nil table:nil]];
416   }
419 - (IBAction)toggleMute:(id)sender
421   if (sender == muteButton)
422     muted = [muteButton state];
423   else
424     muted = !muted;
425   
426   [muteButton setState:muted];
427   [gameView setMuted:muted];
428   [game setMuted:muted];
429   
430   if (muted)
431     [muteMenuItem setTitle:[[NSBundle mainBundle]
432                             localizedStringForKey:@"UnMuteGameMenuItemTitle"
433                             value:nil table:nil]];
434   else
435     [muteMenuItem setTitle:[[NSBundle mainBundle]
436                             localizedStringForKey:@"MuteGameMenuItemTitle"
437                             value:nil table:nil]];
438   
441 - (IBAction)orderFrontAboutPanel:(id)sender
443   #pragma unused (sender)
444   
445   //NSLog(@"GameController showAboutPanel called");
446   if (!aboutPanel)
447     [NSBundle loadNibNamed:@"About" owner:self];
448   [aboutPanel setFrameAutosaveName:@"aboutPanel"];
449   [aboutPanel makeKeyAndOrderFront:self];
452 - (IBAction)orderFrontPreferencesPanel:(id)sender
454   #pragma unused (sender)
455   
456   if (!prefsPanel) {
457     [NSBundle loadNibNamed:@"Preferences" owner:self];
458   }
459   
460   [prefsStandardGraphicsButton setState:!useAlternateGraphics];
461   [prefsAlternateGraphicsButton setState:useAlternateGraphics];
462   
463   [prefsCustomBackgroundCheckbox setState:useCustomBackgrounds];
464   [prefsCustomBackgroundFolderTextField setStringValue:customBackgroundFolderPath];
465   [prefsSelectFolderButton setEnabled:[prefsCustomBackgroundCheckbox state]];
466   [prefsCustomBackgroundFolderTextField setEnabled:[prefsCustomBackgroundCheckbox state]];
467   
468   if ([[NSUserDefaults standardUserDefaults]    dataForKey:@"tiffGemImage0"])
469   {    // set up images!
470     int i = 0;
471     for (i = 0; i < 7; i++)
472     {
473       NSString  *key = [NSString stringWithFormat:@"tiffGemImage%d", i];
474       NSData    *tiffData = [[NSUserDefaults standardUserDefaults]      dataForKey:key];
475       NSImage   *gemImage = [[NSImage alloc] initWithData:tiffData];
476       if (i == 0)       [iv1 setImage:gemImage];
477       if (i == 1)       [iv2 setImage:gemImage];
478       if (i == 2)       [iv3 setImage:gemImage];
479       if (i == 3)       [iv4 setImage:gemImage];
480       if (i == 4)       [iv5 setImage:gemImage];
481       if (i == 5)       [iv6 setImage:gemImage];
482       if (i == 6)       [iv7 setImage:gemImage];
483       [gemImage release];
484     }
485   }
486   
487   [prefsPanel setFrameAutosaveName:@"prefsPanel"];
488   [prefsPanel makeKeyAndOrderFront:self];
491 - (IBAction)showHighScores:(id)sender
493   #pragma unused (sender)
494   
495   // rotate which scores to show
496   gameNames = [hiScores objectAtIndex:gameLevel*2];
497   gameScores = [hiScores objectAtIndex:gameLevel*2+1];
498   if (gameLevel==0)
499     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
500                                     localizedStringForKey:@"EasyHighScoresHTML"
501                                     value:nil table:nil]];
502   else if (gameLevel==1)
503     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
504                                     localizedStringForKey:@"HardHighScoresHTML"
505                                     value:nil table:nil]];
506   else if (gameLevel==2)
507     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
508                                     localizedStringForKey:@"ToughHighScoresHTML"
509                                     value:nil table:nil]];
510   else if (gameLevel==3)
511     [gameView setHTMLHiScoreLegend:[[NSBundle mainBundle]
512                                     localizedStringForKey:@"FreePlayHighScoresHTML"
513                                     value:nil table:nil]];
514   gameLevel = (gameLevel +1)%4;
515   
516   [gameView showHighScores:gameScores andNames:gameNames];
517   [gameView setLastMoveDate];   //reset timer so scores show for 20s    
520 - (IBAction)resetHighScores:(id)sender
522   // don't rotate which scores to show
523   //
524   // blank the hi scores
525   //
526   [hiScores release];
527   hiScores = [[self makeBlankHiScoresWith:nil] retain];
528   [[NSUserDefaults standardUserDefaults] setObject:hiScores forKey:@"hiScores"];
529   
530   [self showHighScores:sender]; //call the show scores routine    
533 - (NSArray *)makeBlankHiScoresWith:(NSArray *)oldScores
535   //int i,j;
536   int j;
537   NSMutableArray        *result = [NSMutableArray arrayWithCapacity:0];
538   
539   if (oldScores)        result = [NSMutableArray arrayWithArray:oldScores];
540   
541   //for (i = 0; i < 3; i++)
542   while ([result count] < 8)
543   {
544     NSMutableArray      *scores = [NSMutableArray arrayWithCapacity:0];
545     NSMutableArray      *names = [NSMutableArray arrayWithCapacity:0];
546     for (j = 0; j < 10; j++)
547     {
548       [scores addObject:[NSNumber numberWithInt:1000]];
549       [names addObject:[[NSBundle mainBundle]
550                         localizedStringForKey:@"AnonymousName"
551                         value:nil table:nil]];
552     }
553     [result addObject:names];
554     [result addObject:scores];
555   }
556   return [NSArray arrayWithArray:result];
559 - (void)runOutOfTime
561   gameState = GAMESTATE_GAMEOVER;
562   [abortGameButton setEnabled:NO];
563   [pauseGameButton setEnabled:NO];
564   abortGame = YES;
565   [gameView setHTMLLegend:gameOverString];
566   [game shake];
567   [self startAnimation:@selector(waitForFirstClick)];
570 - (void)checkHiScores
572   int i;
573   // reset arrays with gameLevel
574   gameNames = [hiScores objectAtIndex:gameLevel*2];
575   gameScores = [hiScores objectAtIndex:gameLevel*2+1];
576   for (i = 0; i < 10; i++)
577   {
578     if ([game score] > [[gameScores objectAtIndex:i] intValue])
579     {
580       [hiScorePanelScoreTextField
581        setStringValue:[NSString stringWithFormat:@"%d",[game score]]];
582       [NSApp    beginSheet:hiScorePanel
583          modalForWindow:gameWindow
584           modalDelegate:self
585          didEndSelector:NULL
586             contextInfo:NULL];
587       return;
588     }
589   }
590   [gameView showHighScores:gameScores andNames:gameNames];
593 - (void)bonusAwarded
595   
596   [gameView newBackground];
597   
598   if (!muted)           [[NSSound soundNamed:@"yes"] play];
599   
600   if (!freePlay) {              // FREEPLAY MW
601     [game increaseBonusMultiplier];
602     [timerView decrementMeter:0.5];
603   } else {
604     [game increaseBonusMultiplier];
605     [timerView decrementMeter:1];
606   }
607   
608   if (gameSpeed < SPEED_LIMIT)          // capping speed limit
609     gameSpeed = gameSpeed * 1.5;
610   //NSLog(@"...gamesSpeed %f",gameSpeed);
611   [timerView setTimerRunningEvery:0.5/gameSpeed
612                         decrement:(0.5/gameTime)
613                        withTarget:self
614                        whenRunOut:@selector(runOutOfTime)
615                       whenRunOver:@selector(bonusAwarded)];
616   
617   if (freePlay) [timerView setDecrement:0];//   FREEPLAY
620 - (void)startAnimation:(SEL)andThenSelector
622   [animationTimerLock lock];
623   //
624   if (!timer)
625     timer = [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL
626                                               target:gameView
627                                             selector:@selector(animate)
628                                             userInfo:self
629                                              repeats:YES] retain];
630   //
631   whatNext = andThenSelector;
632   //
633   [gameView setAnimating:YES];
634   //
635   [animationTimerLock unlock];
638 - (void)animationEnded
640   //NSLog(@"gameController.animationEnded messaged");
641   
642   [animationTimerLock lock];
643   //
644   [gameView setAnimating:NO];
645   //
646   [animationTimerLock unlock];
647   
648   if (whatNext) [self performSelector:whatNext];
649   
650   [gameView setNeedsDisplay:YES];
653 - (void)waitForNewGame
655   [self checkHiScores];
656   
657   [game wholeNewGameWithSpritesFrom:[gameView spriteArray]];
658   [gameView setLegend:titleImage];
659   [easyGameButton setEnabled:YES];
660   [hardGameButton setEnabled:YES];
661   [toughGameButton setEnabled:YES];
662   [abortGameButton setEnabled:NO];
663   [pauseGameButton setEnabled:NO];
666 - (void)newBoard1
668   //NSLog(@"newBoard1");
669   [game erupt];
670   [self startAnimation:@selector(newBoard2)];
673 - (void)newBoard2
675   Gem *gem;
676   int r;
677   
678   //NSLog(@"newBoard2");
679   for (int i = 0; i < 8; i++) {
680     for (int j = 0; j < 8; j++) {
681       gem = [game gemAt:i:j];
682       r = rand() % 7;
683       [gem setGemType:r];
684       //[gem setImage:[[gameView imageArray] objectAtIndex:r]];
685       [gem setSprite:[[gameView spriteArray] objectAtIndex:r]];
686       gem._positionOnBoard  = NSMakePoint(i, j);
687       gem._positionOnScreen = NSMakePoint(i * 48, (i + j + 8) * 48);
688       [gem fall];
689     }
690   }
691   [gameView newBackground];
692   [gameView setLegend:nil];
693   [self startAnimation:@selector(testForThreesAgain)];
696 - (void)waitForFirstClick
698   //NSLog(@"waitForFirstClick");
699   /*- if (!freePlay)  MW CHANGE -*/     [timerView setPaused:NO];
700   if (abortGame)
701   {
702     [timerView setTimer:0.5];
703     gameState = GAMESTATE_GAMEOVER;
704     [game explodeGameOver];
705     [self startAnimation:@selector(waitForNewGame)];
706     return;
707   }
708   if (![game boardHasMoves])
709   {
710     [timerView setPaused:YES];
711     [gameView setHTMLLegend:noMoreMovesString];
712     [game shake];
713     
714     if (freePlay)       [self startAnimation:@selector(runOutOfTime)];//        FREEPLAY
715     else                [self startAnimation:@selector(newBoard1)];//   FREEPLAY
716     
717     return;
718   }
719   gameState = GAMESTATE_AWAITINGFIRSTCLICK;
722 - (void)receiveClickAt:(int)x :(int)y
724   if (paused)   return;
725   if ((x < 0)||(x > 383)||(y < 0)||(y > 383))   return;
726   if (gameState == GAMESTATE_AWAITINGFIRSTCLICK)
727   {
728     chxa = floor(x / 48);
729     chya = floor(y / 48);
730     gameState = GAMESTATE_AWAITINGSECONDCLICK;
731     [gameView setNeedsDisplay:YES];
732     return;
733   }
734   if (gameState == GAMESTATE_AWAITINGSECONDCLICK)
735   {
736     chxb = floor(x / 48);
737     chyb = floor(y / 48);
738     if ((chxb != chxa)^(chyb != chya))  // xor!
739     {
740       int d = (chxa - chxb) * (chxa - chxb) + (chya - chyb) * (chya - chyb);
741       //NSLog(@"square distance ==%d",d);
742       if (d==1)
743       {
744         gameState = GAMESTATE_FRACULATING;
745         [gameView setNeedsDisplay:YES];
746         [gameView setLastMoveDate];
747         /*- MW CHANGE if (!freePlay) -*/ [timerView setPaused:YES];
748         [self tryMoveSwapping:chxa:chya and:chxb:chyb];
749         return;
750       }
751     }
752     // fall out of routine setting first click location
753     chxa = floor(x / 48);
754     chya = floor(y / 48);
755     gameState = GAMESTATE_AWAITINGSECONDCLICK;
756     [gameView setNeedsDisplay:YES];
757   }
761 - (void)tryMoveSwapping:(int)xA :(int)yA and:(int)xB :(int)yB
763   // do stuff here!!!
764   int xxa, yya, xxb, yyb;
765   
766   //NSLog(@"tryMoveSwapping");
767   if (xA != xB)
768   {
769     if (xA < xB) {
770       xxa = xA; xxb = xB;
771     }
772     else {
773       xxa = xB; xxb = xA;
774     }
775     
776     yya = yA;
777     yyb = yB;
778   }
779   else
780   {
781     if (yA < yB) {
782       yya = yA; yyb = yB;
783     }
784     else {
785       yya = yB; yyb = yA;
786     }
787     
788     xxa = xA;
789     xxb = xB;
790   }
791   
792   // store swap positions
793   chxa = xxa; chya = yya;
794   chxb = xxb; chyb = yyb;
795   
796   // swap positions
797   if (chxa < chxb) { // swapping horizontally
798     [[game gemAt:chxa:chya] setVelocity:gemMoveSpeed:0:gemMoveSteps];
799     [[game gemAt:chxb:chyb] setVelocity:-gemMoveSpeed:0:gemMoveSteps];
800   }
801   else { // swapping vertically
802     [[game gemAt:chxa:chya] setVelocity:0:gemMoveSpeed:gemMoveSteps];
803     [[game gemAt:chxb:chyb] setVelocity:0:-gemMoveSpeed:gemMoveSteps];
804   }
805   
806   [game swap:chxa:chya and:chxb:chyb];
807   gameState = GAMESTATE_SWAPPING;
808   
809   [self startAnimation:@selector(testForThrees)];
812 - (void)testForThrees
814   BOOL anyThrees;
815   int oldScore = [game score];
816   //NSLog(@"testForThrees");
817   anyThrees = ([game testForThreeAt:chxa:chya])|([game testForThreeAt:chxb:chyb]);
818   [scoreTextField setStringValue:[NSString stringWithFormat:@"%d",[game score]]];
819   [scoreTextField setNeedsDisplay:YES];
820   [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d",[game bonusMultiplier]]];
821   [bonusTextField setNeedsDisplay:YES];
822   if ([game score] > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS];
823   if (anyThrees) {
824     [self startAnimation:@selector(removeThreesAndReplaceGems)];        // fade gems
825   }
826   else {
827     [self unSwap];
828   }
829 }    
831 //// repeat:    remove threes
832 - (void)removeThreesAndReplaceGems
834   
835   //NSLog(@"removeThreesAndReplaceGems");
836   // deal with fading
837   [game removeFadedGemsAndReorganiseWithSpritesFrom:[gameView spriteArray]];
838   
839   [self startAnimation:@selector(testForThreesAgain)];  // gems fall down
840 }    
842 - (void)testForThreesAgain
844   BOOL anyThrees;
845   int oldScore = [game score];
846   //NSLog(@"testForThreesAgain");
847   anyThrees = [game checkBoardForThrees];
848   [scoreTextField setStringValue:[NSString stringWithFormat:@"%d",[game score]]];
849   [scoreTextField setNeedsDisplay:YES];
850   [bonusTextField setStringValue:[NSString stringWithFormat:@"x%d",[game bonusMultiplier]]];
851   [bonusTextField setNeedsDisplay:YES];
852   if ([game score] > oldScore) [timerView incrementMeter:[game collectGemsFaded]/GEMS_FOR_BONUS];
853   if (anyThrees)
854     [self startAnimation:@selector(removeThreesAndReplaceGems)];        // fade gems
855   else
856     [self waitForFirstClick];
857 }   
858 ////            allow gems to fall
859 ////            test for threes
860 //// until there are no threes
862 - (void)unSwap
864   //NSLog(@"unSwap");
865   
866   if (!muted)   [[NSSound soundNamed:@"no"] play];
867   
868   // swap positions
869   if (chxa < chxb) { // swapping horizontally
870     [[game gemAt:chxa:chya] setVelocity:4:0:12];
871     [[game gemAt:chxb:chyb] setVelocity:-4:0:12];
872   }
873   else { // swapping vertically
874     [[game gemAt:chxa:chya] setVelocity:0:4:12];
875     [[game gemAt:chxb:chyb] setVelocity:0:-4:12];
876   }
877   
878   [game swap:chxa:chya and:chxa:chya];
879   gameState = GAMESTATE_SWAPPING;
880   [self startAnimation:@selector(waitForFirstClick)];
881 }    
884 - (int) gameState {
885   return gameState;
888 - (BOOL) gameIsPaused {
889   return paused;
892 - (BOOL) useCustomBackgrounds {
893   return useCustomBackgrounds;
896 - (NSPoint) crossHair1Position {
897   return NSMakePoint(chxa * 48,chya * 48);
900 - (NSPoint) crossHair2Position {
901   return NSMakePoint(chxb * 48,chyb * 48);
904 @end