1 /* ----====----====----====----====----====----====----====----====----====----
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 ----====----====----====----====----====----====----====----====----====---- */
27 #import "ScoreBubble.h"
37 for (i = 0; i < 8; i++)
38 for (j = 0; j < 8; j++)
39 board[i][j] = [[Gem alloc] init];
41 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
46 - (id) initWithImagesFrom:(NSArray *) imageArray
50 srand([[NSDate date] timeIntervalSince1970]); // seed by time
51 for (i = 0; i < 8; i++)
52 for (j = 0; j < 8; j++)
54 int r = [self randomGemTypeAt:i:j];
55 board[i][j] = [[Gem gemWithNumber:r andImage:[imageArray objectAtIndex:r]] retain];
56 [board[i][j] setPositionOnBoard:i:j];
57 [board[i][j] setPositionOnScreen:i*48:j*48];
61 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
69 - (id) initWithSpritesFrom:(NSArray *) spriteArray
73 srand([[NSDate date] timeIntervalSince1970]); // seed by time
74 for (i = 0; i < 8; i++)
75 for (j = 0; j < 8; j++)
77 //int r = (rand() % 3)*2+((i+j)%2);
78 int r = [self randomGemTypeAt:i:j];
79 board[i][j] = [[Gem gemWithNumber:r andSprite:[spriteArray objectAtIndex:r]] retain];
80 [board[i][j] setPositionOnBoard:i:j];
81 [board[i][j] setPositionOnScreen:i*48:j*48];
85 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
96 for (i = 0; i < 8; i++)
97 for (j = 0; j < 8; j++)
98 [board[i][j] release];
100 [scoreBubbles release];
105 - (void) setImagesFrom:(NSArray *) imageArray
108 for (i = 0; i < 8; i++)
109 for (j = 0; j < 8; j++)
110 [board[i][j] setImage:[imageArray objectAtIndex:[board[i][j] gemType]]];
113 - (void) setSpritesFrom:(NSArray *) spriteArray
116 for (i = 0; i < 8; i++)
117 for (j = 0; j < 8; j++)
118 [board[i][j] setSprite:[spriteArray objectAtIndex:[board[i][j] gemType]]];
121 - (int) randomGemTypeAt:(int)x :(int)y
126 return (r & 6); // even
128 return 1; // catch returning 7
129 return (r | 1); // odd
132 - (Gem *) gemAt:(int)x :(int)y
140 - (NSMutableArray *)scoreBubbles
147 - (void) setMuted:(BOOL)value
152 for (i = 0; i < 8; i++)
153 for (j = 0; j < 8; j++)
154 [board[i][j] setSoundsTink:NULL Sploink:NULL];
156 for (i = 0; i < 8; i++)
157 for (j = 0; j < 8; j++)
158 [board[i][j] setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]];
162 - (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2
164 Gem *swap = board[x1][y1];
165 board[x1][y1] = board[x2][y2];
166 [board[x1][y1] setPositionOnBoard:x1:y1];
167 board[x2][y2] = swap;
168 [board[x2][y2] setPositionOnBoard:x2:y2];
169 sx1 = x1; sx2 = x2; sy1 = y1; sy2 = y2;
174 [self swap:sx1:sy1 and:sx2:sy2];
177 - (BOOL) testForThreeAt:(int) x :(int) y
180 int bonus, linebonus, scorePerGem;
181 float scorebubble_x = -1.0;
182 float scorebubble_y = -1.0;
184 int gemtype = [board[x][y] gemType];
185 tx = x; ty = y; cx = x; cy = y;
187 if ([board[x][y] state] == GEMSTATE_FADING) result = YES;
188 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
189 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
195 scorePerGem = (cx-tx)*5;
196 for (i = tx; i <= cx; i++)
198 linebonus+= scorePerGem;
200 for (j=7; j>y; j--) {
201 if ([board[i][j] state]!= GEMSTATE_FADING) {
202 [board[i][j] shiver]; // MW prepare to fall
206 // to center scorebubble ...
207 scorebubble_x = tx + (cx-tx)/2.0;
213 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
214 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
220 scorePerGem = (cy-ty)*5;
221 for (i = ty; i <= cy; i++)
223 linebonus += scorePerGem;
226 for (j=7; j>cy; j--) {
227 if ([board[x][j] state]!= GEMSTATE_FADING) {
228 [board[x][j] shiver]; // MW prepare to fall
231 // to center scorebubble ...
232 if (scorebubble_x < 0) // only if one hasn't been placed already ! (for T and L shapes)
235 scorebubble_y = ty + (cy-ty)/2.0;
237 else // select the original gem position
253 [scoreBubbles addObject:[ScoreBubble scoreWithValue:bonus*bonusMultiplier
254 At:NSMakePoint(scorebubble_x*48+24, scorebubble_y*48+24)
257 score += bonus * bonusMultiplier;
261 - (BOOL) finalTestForThreeAt:(int) x :(int) y
265 int gemtype = [board[x][y] gemType];
266 tx = x; ty = y; cx = x; cy = y;
268 if ([board[x][y] state] == GEMSTATE_FADING) return YES;
270 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
271 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
276 for (i = tx; i <= cx; i++)
280 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
281 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
286 for (i = ty; i <= cy; i++)
293 - (BOOL) checkForThreeAt:(int) x :(int) y
296 int gemtype = [board[x][y] gemType];
297 tx = x; ty = y; cx = x; cy = y;
298 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
299 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
302 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
303 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
309 - (BOOL) checkBoardForThrees
313 // CASCADE BONUS increase
316 for (i = 0; i < 8; i++)
317 for (j = 0; j < 8; j++)
318 if ([board[i][j] state]!=GEMSTATE_FADING)
319 result = result | [self testForThreeAt:i:j];
320 // CASCADE BONUS check for reset
321 if (!result) cascade = 1;
326 - (void) showAllBoardMoves
328 // test every possible move
332 for (j = 0; j < 8; j++)
333 for (i = 0; i < 7; i++)
335 [self swap:i:j and:i+1:j];
336 [self finalTestForThreeAt:i:j];
337 [self finalTestForThreeAt:i+1:j];
342 for (i = 0; i < 8; i++)
343 for (j = 0; j < 7; j++)
345 [self swap:i:j and:i:j+1];
346 [self finalTestForThreeAt:i:j];
347 [self finalTestForThreeAt:i:j+1];
351 // over the entire board, set the animationtime for the marked gems higher
352 for (i = 0; i < 8; i++)
353 for (j = 0; j < 8; j++)
355 if ([board[i][j] state] == GEMSTATE_FADING)
358 [board[i][j] setAnimationCounter:1];
367 - (BOOL) boardHasMoves
369 // test every possible move
373 for (j = 0; j < 8; j++)
374 for (i = 0; i < 7; i++)
376 [self swap:i:j and:i+1:j];
377 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i+1:j];
388 for (i = 0; i < 8; i++)
389 for (j = 0; j < 7; j++)
391 [self swap:i:j and:i:j+1];
392 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i:j+1];
404 - (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray
407 for (i = 0; i < 8; i++)
412 // let non-faded gems fall into place
413 for (j = 0; j < 8; j++)
415 if ([board[i][j] state] != GEMSTATE_FADING)
417 column[y] = board[i][j];
418 if ([board[i][j] positionOnScreen].y > y*48)
425 // transfer faded gems to top of column
426 for (j = 0; j < 8; j++)
428 if ([board[i][j] state] == GEMSTATE_FADING)
431 int r = (rand() % 7);
432 [board[i][j] setGemType:r];
433 [board[i][j] setImage:[imageArray objectAtIndex:r]];
435 column[y] = board[i][j];
436 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
443 // OK, shuffling all done - reorganise column
444 for (j = 0; j < 8; j++)
446 board[i][j] = column[j];
447 [board[i][j] setPositionOnBoard:i:j];
452 - (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray
455 for (i = 0; i < 8; i++)
460 // let non-faded gems fall into place
461 for (j = 0; j < 8; j++)
463 if ([board[i][j] state] != GEMSTATE_FADING)
465 column[y] = board[i][j];
466 if ([board[i][j] positionOnScreen].y > y*48)
473 // transfer faded gems to top of column
474 for (j = 0; j < 8; j++)
476 if ([board[i][j] state] == GEMSTATE_FADING)
479 int r = (rand() % 7);
480 [board[i][j] setGemType:r];
481 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
483 column[y] = board[i][j];
484 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
491 // OK, shuffling all done - reorganise column
492 for (j = 0; j < 8; j++)
494 board[i][j] = column[j];
495 [board[i][j] setPositionOnBoard:i:j];
503 for (i = 0; i < 8; i++)
504 for (j = 0; j < 8; j++)
511 if (!muted) [[NSSound soundNamed:@"yes"] play];
512 for (i = 0; i < 8; i++)
513 for (j = 0; j < 8; j++)
517 - (void) explodeGameOver
520 if (!muted) [[NSSound soundNamed:@"explosion"] play];
522 for (i = 0; i < 8; i++)
523 for (j = 0; j < 8; j++)
526 [self showAllBoardMoves]; // does a delayed eruption
529 - (void) wholeNewGameWithImagesFrom:(NSArray *) imageArray
532 srand([[NSDate date] timeIntervalSince1970]); // seed by time
533 for (i = 0; i < 8; i++)
534 for (j = 0; j < 8; j++)
536 //int r = (rand() % 3)*2+((i+j)%2);
537 int r = [self randomGemTypeAt:i:j];
538 [board[i][j] setGemType:r];
539 [board[i][j] setImage:[imageArray objectAtIndex:r]];
540 [board[i][j] setPositionOnBoard:i:j];
541 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
549 - (void) wholeNewGameWithSpritesFrom:(NSArray *) spriteArray
552 srand([[NSDate date] timeIntervalSince1970]); // seed by time
553 for (i = 0; i < 8; i++)
554 for (j = 0; j < 8; j++)
556 //int r = (rand() % 3)*2+((i+j)%2);
557 int r = [self randomGemTypeAt:i:j];
558 [board[i][j] setGemType:r];
559 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
560 [board[i][j] setPositionOnBoard:i:j];
561 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
569 - (NSPoint) hintPoint
571 return NSMakePoint(hintx*48,hinty*48);
574 - (float) collectGemsFaded
576 float result = (float)gemsFaded;
586 - (int) bonusMultiplier
588 return bonusMultiplier;
591 - (void) increaseBonusMultiplier