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 ----====----====----====----====----====----====----====----====----====---- */
26 #import "ScoreBubble.h"
30 @synthesize score = _score;
31 @synthesize bonusMultiplier = _bonusMultiplier;
40 for (int i = 0; i < 8; i++) {
41 for (int j = 0; j < 8; j++) {
42 board[i][j] = [[Gem alloc] init];
47 scoreBubbles = [[NSMutableArray arrayWithCapacity:12] retain];
53 - (id)initWithImagesFrom:(NSArray *)imageArray
57 srand([[NSDate date] timeIntervalSince1970]); // seed by time
58 for (int i = 0; i < 8; i++) {
59 for (int j = 0; j < 8; j++) {
60 int r = [self randomGemTypeAt:i:j];
61 Gem *gem = [[Gem gemWithNumber:r andImage:[imageArray objectAtIndex:r]] retain];
63 [gem setPositionOnBoard:i:j];
64 [gem setPositionOnScreen:i*48:j*48];
70 scoreBubbles = [[NSMutableArray arrayWithCapacity:12] retain];
80 - (id)initWithSpritesFrom:(NSArray *)spriteArray
84 srand([[NSDate date] timeIntervalSince1970]); // seed by time
85 for (int i = 0; i < 8; i++) {
86 for (int j = 0; j < 8; j++) {
87 //int r = (rand() % 3)*2+((i+j)%2);
88 int r = [self randomGemTypeAt:i:j];
89 board[i][j] = [[Gem gemWithNumber:r andSprite:[spriteArray objectAtIndex:r]] retain];
90 [board[i][j] setPositionOnBoard:i:j];
91 [board[i][j] setPositionOnScreen:i*48:j*48];
97 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
101 _bonusMultiplier = 1;
109 for (int i = 0; i < 8; i++) {
110 for (int j = 0; j < 8; j++) {
111 [board[i][j] release];
116 [scoreBubbles release];
121 - (void)setImagesFrom:(NSArray *)imageArray
123 for (int i = 0; i < 8; i++) {
124 for (int j = 0; j < 8; j++) {
125 Gem *gem = board[i][j];
126 gem.image = [imageArray objectAtIndex:[gem gemType]];
131 - (void)setSpritesFrom:(NSArray *)spriteArray
133 for (int i = 0; i < 8; i++) {
134 for (int j = 0; j < 8; j++) {
135 Gem *gem = board[i][j];
136 [gem setSprite:[spriteArray objectAtIndex:[gem gemType]]];
141 - (int)randomGemTypeAt:(int)x :(int)y
146 return (r & 6); // even
148 return 1; // catch returning 7
149 return (r | 1); // odd
152 - (Gem *)gemAt:(int)x :(int)y {
157 - (NSMutableArray *)scoreBubbles {
161 - (void)setMuted:(BOOL)value
165 for (int i = 0; i < 8; i++) {
166 for (int j = 0; j < 8; j++) {
167 Gem *gem = board[i][j];
169 gem.tinkSound = NULL;
170 gem.sploinkSound = NULL;
175 for (int i = 0; i < 8; i++) {
176 for (int j = 0; j < 8; j++) {
177 Gem *gem = board[i][j];
180 gem.tinkSound = [NSSound soundNamed:@"tink"];
181 gem.sploinkSound = [NSSound soundNamed:@"sploink"];
187 - (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2
189 Gem *swap = board[x1][y1];
190 board[x1][y1] = board[x2][y2];
191 [board[x1][y1] setPositionOnBoard:x1:y1];
192 board[x2][y2] = swap;
193 [board[x2][y2] setPositionOnBoard:x2:y2];
194 sx1 = x1; sx2 = x2; sy1 = y1; sy2 = y2;
198 [self swap:sx1:sy1 and:sx2:sy2];
201 - (BOOL) testForThreeAt:(int) x :(int) y
204 int bonus, linebonus, scorePerGem;
205 float scorebubble_x = -1.0;
206 float scorebubble_y = -1.0;
208 int gemtype = [board[x][y] gemType];
209 tx = x; ty = y; cx = x; cy = y;
211 if (board[x][y].state == GEMSTATE_FADING) result = YES;
212 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
213 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
219 scorePerGem = (cx-tx)*5;
220 for (i = tx; i <= cx; i++)
222 linebonus+= scorePerGem;
224 for (j=7; j>y; j--) {
225 if (board[i][j].state != GEMSTATE_FADING) {
226 [board[i][j] shiver]; // MW prepare to fall
230 // to center scorebubble ...
231 scorebubble_x = tx + (cx-tx)/2.0;
237 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
238 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
244 scorePerGem = (cy-ty)*5;
245 for (i = ty; i <= cy; i++)
247 linebonus += scorePerGem;
250 for (j=7; j>cy; j--) {
251 if (board[x][j].state != GEMSTATE_FADING) {
252 [board[x][j] shiver]; // MW prepare to fall
255 // to center scorebubble ...
256 if (scorebubble_x < 0) // only if one hasn't been placed already ! (for T and L shapes)
259 scorebubble_y = ty + (cy-ty)/2.0;
261 else // select the original gem position
278 [scoreBubbles addObject:[ScoreBubble scoreWithValue:(bonus * _bonusMultiplier)
279 at:NSMakePoint(scorebubble_x*48+24, scorebubble_y*48+24)
282 _score += bonus * _bonusMultiplier;
286 - (BOOL) finalTestForThreeAt:(int) x :(int) y
290 int gemtype = [board[x][y] gemType];
291 tx = x; ty = y; cx = x; cy = y;
293 if (board[x][y].state == GEMSTATE_FADING) return YES;
295 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
296 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
301 for (i = tx; i <= cx; i++)
305 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
306 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
311 for (i = ty; i <= cy; i++)
318 - (BOOL) checkForThreeAt:(int) x :(int) y
321 int gemtype = [board[x][y] gemType];
322 tx = x; ty = y; cx = x; cy = y;
323 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
324 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
327 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
328 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
334 - (BOOL)checkBoardForThrees
338 // CASCADE BONUS increase
341 for (int i = 0; i < 8; i++) {
342 for (int j = 0; j < 8; j++) {
343 if (board[i][j].state != GEMSTATE_FADING) {
344 result = result | [self testForThreeAt:i:j];
349 // CASCADE BONUS check for reset
357 - (void)showAllBoardMoves
359 // test every possible move
363 for (j = 0; j < 8; j++)
364 for (i = 0; i < 7; i++)
366 [self swap:i:j and:i+1:j];
367 [self finalTestForThreeAt:i:j];
368 [self finalTestForThreeAt:i+1:j];
373 for (i = 0; i < 8; i++)
374 for (j = 0; j < 7; j++)
376 [self swap:i:j and:i:j+1];
377 [self finalTestForThreeAt:i:j];
378 [self finalTestForThreeAt:i:j+1];
382 // over the entire board, set the animationtime for the marked gems higher
383 for (i = 0; i < 8; i++)
384 for (j = 0; j < 8; j++)
386 if (board[i][j].state == GEMSTATE_FADING)
389 // !!!: remove: [board[i][j] setAnimationCounter:1];
390 board[i][j].animationCounter = 1;
399 - (BOOL)boardHasMoves
401 // test every possible move
405 for (int j = 0; j < 8; j++) {
406 for (int i = 0; i < 7; i++) {
407 [self swap:i:j and:i+1:j];
408 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i+1:j];
419 for (int i = 0; i < 8; i++) {
420 for (int j = 0; j < 7; j++) {
421 [self swap:i:j and:i:j+1];
422 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i:j+1];
435 - (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray
438 for (i = 0; i < 8; i++)
443 // let non-faded gems fall into place
444 for (j = 0; j < 8; j++)
446 if (board[i][j].state != GEMSTATE_FADING)
448 column[y] = board[i][j];
449 if ([board[i][j] positionOnScreen].y > y*48)
456 // transfer faded gems to top of column
457 for (j = 0; j < 8; j++)
459 if (board[i][j].state == GEMSTATE_FADING)
462 int r = (rand() % 7);
463 [board[i][j] setGemType:r];
464 board[i][j].image = [imageArray objectAtIndex:r];
466 column[y] = board[i][j];
467 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
474 // OK, shuffling all done - reorganise column
475 for (j = 0; j < 8; j++)
477 board[i][j] = column[j];
478 [board[i][j] setPositionOnBoard:i:j];
483 - (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray
486 for (i = 0; i < 8; i++)
491 // let non-faded gems fall into place
492 for (j = 0; j < 8; j++)
494 if (board[i][j].state != GEMSTATE_FADING)
496 column[y] = board[i][j];
497 if ([board[i][j] positionOnScreen].y > y*48)
504 // transfer faded gems to top of column
505 for (j = 0; j < 8; j++)
507 if (board[i][j].state == GEMSTATE_FADING)
510 int r = (rand() % 7);
511 [board[i][j] setGemType:r];
512 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
514 column[y] = board[i][j];
515 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
522 // OK, shuffling all done - reorganise column
523 for (j = 0; j < 8; j++)
525 board[i][j] = column[j];
526 [board[i][j] setPositionOnBoard:i:j];
533 for (int i = 0; i < 8; i++) {
534 for (int j = 0; j < 8; j++) {
543 [[NSSound soundNamed:@"yes"] play];
546 for (int i = 0; i < 8; i++) {
547 for (int j = 0; j < 8; j++) {
553 - (void) explodeGameOver
556 if (!muted) [[NSSound soundNamed:@"explosion"] play];
558 for (i = 0; i < 8; i++)
559 for (j = 0; j < 8; j++)
562 [self showAllBoardMoves]; // does a delayed eruption
565 - (void)wholeNewGameWithImagesFrom:(NSArray *)imageArray
567 srand([[NSDate date] timeIntervalSince1970]); // seed by time
569 for (int i = 0; i < 8; i++) {
570 for (int j = 0; j < 8; j++) {
571 //int r = (rand() % 3)*2+((i+j)%2);
572 int r = [self randomGemTypeAt:i:j];
574 [board[i][j] setGemType:r];
575 board[i][j].image = [imageArray objectAtIndex:r];
576 [board[i][j] setPositionOnBoard:i:j];
577 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
584 _bonusMultiplier = 1;
587 - (void)wholeNewGameWithSpritesFrom:(NSArray *)spriteArray
589 srand([[NSDate date] timeIntervalSince1970]); // seed by time
591 for (int i = 0; i < 8; i++) {
592 for (int j = 0; j < 8; j++) {
593 //int r = (rand() % 3)*2+((i+j)%2);
594 int r = [self randomGemTypeAt:i:j];
596 Gem *gem = board[i][j];
598 [gem setSprite:[spriteArray objectAtIndex:r]];
599 [gem setPositionOnBoard:i:j];
600 [gem setPositionOnScreen:i*48:(15-j)*48];
607 _bonusMultiplier = 1;
610 - (NSPoint)hintPoint {
611 return NSMakePoint(hintx * 48, hinty * 48);
614 - (float)collectFadedGems
616 float result = (float)_fadedGems;
621 - (void)increaseBonusMultiplier {