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"]];
161 - (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2
163 Gem *swap = board[x1][y1];
164 board[x1][y1] = board[x2][y2];
165 [board[x1][y1] setPositionOnBoard:x1:y1];
166 board[x2][y2] = swap;
167 [board[x2][y2] setPositionOnBoard:x2:y2];
168 sx1 = x1; sx2 = x2; sy1 = y1; sy2 = y2;
173 [self swap:sx1:sy1 and:sx2:sy2];
176 - (BOOL) testForThreeAt:(int) x :(int) y
179 int bonus, linebonus, scorePerGem;
180 float scorebubble_x = -1.0;
181 float scorebubble_y = -1.0;
183 int gemtype = [board[x][y] gemType];
184 tx = x; ty = y; cx = x; cy = y;
186 if ([board[x][y] state] == GEMSTATE_FADING) result = YES;
187 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
188 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
194 scorePerGem = (cx-tx)*5;
195 for (i = tx; i <= cx; i++)
197 linebonus+= scorePerGem;
199 for (j=7; j>y; j--) {
200 if ([board[i][j] state]!= GEMSTATE_FADING) {
201 [board[i][j] shiver]; // MW prepare to fall
205 // to center scorebubble ...
206 scorebubble_x = tx + (cx-tx)/2.0;
212 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
213 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
219 scorePerGem = (cy-ty)*5;
220 for (i = ty; i <= cy; i++)
222 linebonus += scorePerGem;
225 for (j=7; j>cy; j--) {
226 if ([board[x][j] state]!= GEMSTATE_FADING) {
227 [board[x][j] shiver]; // MW prepare to fall
230 // to center scorebubble ...
231 if (scorebubble_x < 0) // only if one hasn't been placed already ! (for T and L shapes)
234 scorebubble_y = ty + (cy-ty)/2.0;
236 else // select the original gem position
252 [scoreBubbles addObject:[ScoreBubble scoreWithValue:bonus*bonusMultiplier
253 At:NSMakePoint(scorebubble_x*48+24, scorebubble_y*48+24)
256 score += bonus * bonusMultiplier;
260 - (BOOL) finalTestForThreeAt:(int) x :(int) y
264 int gemtype = [board[x][y] gemType];
265 tx = x; ty = y; cx = x; cy = y;
267 if ([board[x][y] state] == GEMSTATE_FADING) return YES;
269 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
270 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
275 for (i = tx; i <= cx; i++)
279 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
280 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
285 for (i = ty; i <= cy; i++)
292 - (BOOL) checkForThreeAt:(int) x :(int) y
295 int gemtype = [board[x][y] gemType];
296 tx = x; ty = y; cx = x; cy = y;
297 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
298 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
301 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
302 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
308 - (BOOL) checkBoardForThrees
312 // CASCADE BONUS increase
315 for (i = 0; i < 8; i++)
316 for (j = 0; j < 8; j++)
317 if ([board[i][j] state]!=GEMSTATE_FADING)
318 result = result | [self testForThreeAt:i:j];
319 // CASCADE BONUS check for reset
320 if (!result) cascade = 1;
325 - (void) showAllBoardMoves
327 // test every possible move
331 for (j = 0; j < 8; j++)
332 for (i = 0; i < 7; i++)
334 [self swap:i:j and:i+1:j];
335 [self finalTestForThreeAt:i:j];
336 [self finalTestForThreeAt:i+1:j];
341 for (i = 0; i < 8; i++)
342 for (j = 0; j < 7; j++)
344 [self swap:i:j and:i:j+1];
345 [self finalTestForThreeAt:i:j];
346 [self finalTestForThreeAt:i:j+1];
350 // over the entire board, set the animationtime for the marked gems higher
351 for (i = 0; i < 8; i++)
352 for (j = 0; j < 8; j++)
354 if ([board[i][j] state] == GEMSTATE_FADING)
357 [board[i][j] setAnimationCounter:1];
366 - (BOOL) boardHasMoves
368 // test every possible move
372 for (j = 0; j < 8; j++)
373 for (i = 0; i < 7; i++)
375 [self swap:i:j and:i+1:j];
376 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i+1:j];
387 for (i = 0; i < 8; i++)
388 for (j = 0; j < 7; j++)
390 [self swap:i:j and:i:j+1];
391 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i:j+1];
403 - (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray
406 for (i = 0; i < 8; i++)
411 // let non-faded gems fall into place
412 for (j = 0; j < 8; j++)
414 if ([board[i][j] state] != GEMSTATE_FADING)
416 column[y] = board[i][j];
417 if ([board[i][j] positionOnScreen].y > y*48)
424 // transfer faded gems to top of column
425 for (j = 0; j < 8; j++)
427 if ([board[i][j] state] == GEMSTATE_FADING)
430 int r = (rand() % 7);
431 [board[i][j] setGemType:r];
432 [board[i][j] setImage:[imageArray objectAtIndex:r]];
434 column[y] = board[i][j];
435 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
442 // OK, shuffling all done - reorganise column
443 for (j = 0; j < 8; j++)
445 board[i][j] = column[j];
446 [board[i][j] setPositionOnBoard:i:j];
451 - (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray
454 for (i = 0; i < 8; i++)
459 // let non-faded gems fall into place
460 for (j = 0; j < 8; j++)
462 if ([board[i][j] state] != GEMSTATE_FADING)
464 column[y] = board[i][j];
465 if ([board[i][j] positionOnScreen].y > y*48)
472 // transfer faded gems to top of column
473 for (j = 0; j < 8; j++)
475 if ([board[i][j] state] == GEMSTATE_FADING)
478 int r = (rand() % 7);
479 [board[i][j] setGemType:r];
480 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
482 column[y] = board[i][j];
483 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
490 // OK, shuffling all done - reorganise column
491 for (j = 0; j < 8; j++)
493 board[i][j] = column[j];
494 [board[i][j] setPositionOnBoard:i:j];
502 for (i = 0; i < 8; i++)
503 for (j = 0; j < 8; j++)
510 if (!muted) [[NSSound soundNamed:@"yes"] play];
511 for (i = 0; i < 8; i++)
512 for (j = 0; j < 8; j++)
516 - (void) explodeGameOver
519 if (!muted) [[NSSound soundNamed:@"explosion"] play];
521 for (i = 0; i < 8; i++)
522 for (j = 0; j < 8; j++)
525 [self showAllBoardMoves]; // does a delayed eruption
528 - (void) wholeNewGameWithImagesFrom:(NSArray *) imageArray
531 srand([[NSDate date] timeIntervalSince1970]); // seed by time
532 for (i = 0; i < 8; i++)
533 for (j = 0; j < 8; j++)
535 //int r = (rand() % 3)*2+((i+j)%2);
536 int r = [self randomGemTypeAt:i:j];
537 [board[i][j] setGemType:r];
538 [board[i][j] setImage:[imageArray objectAtIndex:r]];
539 [board[i][j] setPositionOnBoard:i:j];
540 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
548 - (void) wholeNewGameWithSpritesFrom:(NSArray *) spriteArray
551 srand([[NSDate date] timeIntervalSince1970]); // seed by time
552 for (i = 0; i < 8; i++)
553 for (j = 0; j < 8; j++)
555 //int r = (rand() % 3)*2+((i+j)%2);
556 int r = [self randomGemTypeAt:i:j];
557 [board[i][j] setGemType:r];
558 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
559 [board[i][j] setPositionOnBoard:i:j];
560 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
568 - (NSPoint) hintPoint
570 return NSMakePoint(hintx*48,hinty*48);
573 - (float) collectGemsFaded
575 float result = (float)gemsFaded;
585 - (int) bonusMultiplier
587 return bonusMultiplier;
590 - (void) increaseBonusMultiplier