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"
37 for (int i = 0; i < 8; i++) {
38 for (int j = 0; j < 8; j++) {
39 board[i][j] = [[Gem alloc] init];
44 scoreBubbles = [[NSMutableArray arrayWithCapacity:12] retain];
50 - (id)initWithImagesFrom:(NSArray *)imageArray
54 srand([[NSDate date] timeIntervalSince1970]); // seed by time
55 for (int i = 0; i < 8; i++) {
56 for (int j = 0; j < 8; j++) {
57 int r = [self randomGemTypeAt:i:j];
58 Gem *gem = [[Gem gemWithNumber:r andImage:[imageArray objectAtIndex:r]] retain];
60 [gem setPositionOnBoard:i:j];
61 [gem setPositionOnScreen:i*48:j*48];
67 scoreBubbles = [[NSMutableArray arrayWithCapacity:12] retain];
77 - (id)initWithSpritesFrom:(NSArray *)spriteArray
81 srand([[NSDate date] timeIntervalSince1970]); // seed by time
82 for (int i = 0; i < 8; i++) {
83 for (int j = 0; j < 8; j++) {
84 //int r = (rand() % 3)*2+((i+j)%2);
85 int r = [self randomGemTypeAt:i:j];
86 board[i][j] = [[Gem gemWithNumber:r andSprite:[spriteArray objectAtIndex:r]] retain];
87 [board[i][j] setPositionOnBoard:i:j];
88 [board[i][j] setPositionOnScreen:i*48:j*48];
94 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
106 for (int i = 0; i < 8; i++) {
107 for (int j = 0; j < 8; j++) {
108 [board[i][j] release];
113 [scoreBubbles release];
118 - (void)setImagesFrom:(NSArray *)imageArray
120 for (int i = 0; i < 8; i++) {
121 for (int j = 0; j < 8; j++) {
122 Gem *gem = board[i][j];
123 [gem setImage:[imageArray objectAtIndex:[gem gemType]]];
128 - (void)setSpritesFrom:(NSArray *)spriteArray
130 for (int i = 0; i < 8; i++) {
131 for (int j = 0; j < 8; j++) {
132 Gem *gem = board[i][j];
133 [gem setSprite:[spriteArray objectAtIndex:[gem gemType]]];
138 - (int)randomGemTypeAt:(int)x :(int)y
143 return (r & 6); // even
145 return 1; // catch returning 7
146 return (r | 1); // odd
149 - (Gem *)gemAt:(int)x :(int)y {
154 - (NSMutableArray *)scoreBubbles {
158 - (void)setMuted:(BOOL)value
162 for (int i = 0; i < 8; i++) {
163 for (int j = 0; j < 8; j++) {
164 [board[i][j] setSoundsTink:NULL Sploink:NULL];
169 for (int i = 0; i < 8; i++) {
170 for (int j = 0; j < 8; j++) {
171 [board[i][j] setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]];
177 - (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2
179 Gem *swap = board[x1][y1];
180 board[x1][y1] = board[x2][y2];
181 [board[x1][y1] setPositionOnBoard:x1:y1];
182 board[x2][y2] = swap;
183 [board[x2][y2] setPositionOnBoard:x2:y2];
184 sx1 = x1; sx2 = x2; sy1 = y1; sy2 = y2;
188 [self swap:sx1:sy1 and:sx2:sy2];
191 - (BOOL) testForThreeAt:(int) x :(int) y
194 int bonus, linebonus, scorePerGem;
195 float scorebubble_x = -1.0;
196 float scorebubble_y = -1.0;
198 int gemtype = [board[x][y] gemType];
199 tx = x; ty = y; cx = x; cy = y;
201 if (board[x][y]._state == GEMSTATE_FADING) result = YES;
202 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
203 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
209 scorePerGem = (cx-tx)*5;
210 for (i = tx; i <= cx; i++)
212 linebonus+= scorePerGem;
214 for (j=7; j>y; j--) {
215 if (board[i][j]._state != GEMSTATE_FADING) {
216 [board[i][j] shiver]; // MW prepare to fall
220 // to center scorebubble ...
221 scorebubble_x = tx + (cx-tx)/2.0;
227 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
228 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
234 scorePerGem = (cy-ty)*5;
235 for (i = ty; i <= cy; i++)
237 linebonus += scorePerGem;
240 for (j=7; j>cy; j--) {
241 if (board[x][j]._state != GEMSTATE_FADING) {
242 [board[x][j] shiver]; // MW prepare to fall
245 // to center scorebubble ...
246 if (scorebubble_x < 0) // only if one hasn't been placed already ! (for T and L shapes)
249 scorebubble_y = ty + (cy-ty)/2.0;
251 else // select the original gem position
268 [scoreBubbles addObject:[ScoreBubble scoreWithValue:(bonus * _bonusMultiplier)
269 at:NSMakePoint(scorebubble_x*48+24, scorebubble_y*48+24)
272 _score += bonus * _bonusMultiplier;
276 - (BOOL) finalTestForThreeAt:(int) x :(int) y
280 int gemtype = [board[x][y] gemType];
281 tx = x; ty = y; cx = x; cy = y;
283 if (board[x][y]._state == GEMSTATE_FADING) return YES;
285 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
286 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
291 for (i = tx; i <= cx; i++)
295 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
296 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
301 for (i = ty; i <= cy; i++)
308 - (BOOL) checkForThreeAt:(int) x :(int) y
311 int gemtype = [board[x][y] gemType];
312 tx = x; ty = y; cx = x; cy = y;
313 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
314 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
317 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
318 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
324 - (BOOL)checkBoardForThrees
328 // CASCADE BONUS increase
331 for (int i = 0; i < 8; i++) {
332 for (int j = 0; j < 8; j++) {
333 if (board[i][j]._state != GEMSTATE_FADING) {
334 result = result | [self testForThreeAt:i:j];
339 // CASCADE BONUS check for reset
347 - (void) showAllBoardMoves
349 // test every possible move
353 for (j = 0; j < 8; j++)
354 for (i = 0; i < 7; i++)
356 [self swap:i:j and:i+1:j];
357 [self finalTestForThreeAt:i:j];
358 [self finalTestForThreeAt:i+1:j];
363 for (i = 0; i < 8; i++)
364 for (j = 0; j < 7; j++)
366 [self swap:i:j and:i:j+1];
367 [self finalTestForThreeAt:i:j];
368 [self finalTestForThreeAt:i:j+1];
372 // over the entire board, set the animationtime for the marked gems higher
373 for (i = 0; i < 8; i++)
374 for (j = 0; j < 8; j++)
376 if (board[i][j]._state == GEMSTATE_FADING)
379 // !!!: remove: [board[i][j] setAnimationCounter:1];
380 board[i][j]._animationCounter = 1;
389 - (BOOL) boardHasMoves
391 // test every possible move
395 for (j = 0; j < 8; j++)
396 for (i = 0; i < 7; i++)
398 [self swap:i:j and:i+1:j];
399 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i+1:j];
410 for (i = 0; i < 8; i++)
411 for (j = 0; j < 7; j++)
413 [self swap:i:j and:i:j+1];
414 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i:j+1];
426 - (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray
429 for (i = 0; i < 8; i++)
434 // let non-faded gems fall into place
435 for (j = 0; j < 8; j++)
437 if (board[i][j]._state != GEMSTATE_FADING)
439 column[y] = board[i][j];
440 if ([board[i][j] positionOnScreen].y > y*48)
447 // transfer faded gems to top of column
448 for (j = 0; j < 8; j++)
450 if (board[i][j]._state == GEMSTATE_FADING)
453 int r = (rand() % 7);
454 [board[i][j] setGemType:r];
455 [board[i][j] setImage:[imageArray objectAtIndex:r]];
457 column[y] = board[i][j];
458 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
465 // OK, shuffling all done - reorganise column
466 for (j = 0; j < 8; j++)
468 board[i][j] = column[j];
469 [board[i][j] setPositionOnBoard:i:j];
474 - (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray
477 for (i = 0; i < 8; i++)
482 // let non-faded gems fall into place
483 for (j = 0; j < 8; j++)
485 if (board[i][j]._state != GEMSTATE_FADING)
487 column[y] = board[i][j];
488 if ([board[i][j] positionOnScreen].y > y*48)
495 // transfer faded gems to top of column
496 for (j = 0; j < 8; j++)
498 if (board[i][j]._state == GEMSTATE_FADING)
501 int r = (rand() % 7);
502 [board[i][j] setGemType:r];
503 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
505 column[y] = board[i][j];
506 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
513 // OK, shuffling all done - reorganise column
514 for (j = 0; j < 8; j++)
516 board[i][j] = column[j];
517 [board[i][j] setPositionOnBoard:i:j];
524 for (int i = 0; i < 8; i++) {
525 for (int j = 0; j < 8; j++) {
534 [[NSSound soundNamed:@"yes"] play];
537 for (int i = 0; i < 8; i++) {
538 for (int j = 0; j < 8; j++) {
544 - (void) explodeGameOver
547 if (!muted) [[NSSound soundNamed:@"explosion"] play];
549 for (i = 0; i < 8; i++)
550 for (j = 0; j < 8; j++)
553 [self showAllBoardMoves]; // does a delayed eruption
556 - (void) wholeNewGameWithImagesFrom:(NSArray *) imageArray
559 srand([[NSDate date] timeIntervalSince1970]); // seed by time
560 for (i = 0; i < 8; i++)
561 for (j = 0; j < 8; j++)
563 //int r = (rand() % 3)*2+((i+j)%2);
564 int r = [self randomGemTypeAt:i:j];
565 [board[i][j] setGemType:r];
566 [board[i][j] setImage:[imageArray objectAtIndex:r]];
567 [board[i][j] setPositionOnBoard:i:j];
568 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
573 _bonusMultiplier = 1;
576 - (void) wholeNewGameWithSpritesFrom:(NSArray *) spriteArray
579 srand([[NSDate date] timeIntervalSince1970]); // seed by time
580 for (i = 0; i < 8; i++)
581 for (j = 0; j < 8; j++)
583 //int r = (rand() % 3)*2+((i+j)%2);
584 int r = [self randomGemTypeAt:i:j];
585 [board[i][j] setGemType:r];
586 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
587 [board[i][j] setPositionOnBoard:i:j];
588 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
593 _bonusMultiplier = 1;
596 // TODO: set as dynamic readonly property
597 - (NSPoint)hintPoint {
598 return NSMakePoint(hintx * 48, hinty * 48);
601 - (float)collectGemsFaded
603 float result = (float)gemsFaded;
608 - (void) increaseBonusMultiplier