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 ----====----====----====----====----====----====----====----====----====---- */
22 /* kokomonds is a fork of JewelToy.
23 * repository: http://github.com/exterlulz/kokomonds
33 #import "ScoreBubble.h"
43 for (i = 0; i < 8; i++)
44 for (j = 0; j < 8; j++)
45 board[i][j] = [[Gem alloc] init];
47 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
52 - (id) initWithImagesFrom:(NSArray *) imageArray
56 srand([[NSDate date] timeIntervalSince1970]); // seed by time
57 for (i = 0; i < 8; i++)
58 for (j = 0; j < 8; j++)
60 int r = [self randomGemTypeAt:i:j];
61 board[i][j] = [[Gem gemWithNumber:r andImage:[imageArray objectAtIndex:r]] retain];
62 [board[i][j] setPositionOnBoard:i:j];
63 [board[i][j] setPositionOnScreen:i*48:j*48];
67 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
75 - (id) initWithSpritesFrom:(NSArray *) spriteArray
79 srand([[NSDate date] timeIntervalSince1970]); // seed by time
80 for (i = 0; i < 8; i++)
81 for (j = 0; j < 8; j++)
83 //int r = (rand() % 3)*2+((i+j)%2);
84 int r = [self randomGemTypeAt:i:j];
85 board[i][j] = [[Gem gemWithNumber:r andSprite:[spriteArray objectAtIndex:r]] retain];
86 [board[i][j] setPositionOnBoard:i:j];
87 [board[i][j] setPositionOnScreen:i*48:j*48];
91 scoreBubbles= [[NSMutableArray arrayWithCapacity:12] retain];
102 for (i = 0; i < 8; i++)
103 for (j = 0; j < 8; j++)
104 [board[i][j] release];
106 [scoreBubbles release];
111 - (void) setImagesFrom:(NSArray *) imageArray
114 for (i = 0; i < 8; i++)
115 for (j = 0; j < 8; j++)
116 [board[i][j] setImage:[imageArray objectAtIndex:[board[i][j] gemType]]];
119 - (void) setSpritesFrom:(NSArray *) spriteArray
122 for (i = 0; i < 8; i++)
123 for (j = 0; j < 8; j++)
124 [board[i][j] setSprite:[spriteArray objectAtIndex:[board[i][j] gemType]]];
127 - (int) randomGemTypeAt:(int)x :(int)y
132 return (r & 6); // even
134 return 1; // catch returning 7
135 return (r | 1); // odd
138 - (Gem *) gemAt:(int)x :(int)y
146 - (NSMutableArray *)scoreBubbles
153 - (void) setMuted:(BOOL)value
158 for (i = 0; i < 8; i++)
159 for (j = 0; j < 8; j++)
160 [board[i][j] setSoundsTink:NULL Sploink:NULL];
162 for (i = 0; i < 8; i++)
163 for (j = 0; j < 8; j++)
164 [board[i][j] setSoundsTink:[NSSound soundNamed:@"tink"] Sploink:[NSSound soundNamed:@"sploink"]];
168 - (void) swap:(int) x1 :(int) y1 and:(int) x2:(int) y2
170 Gem *swap = board[x1][y1];
171 board[x1][y1] = board[x2][y2];
172 [board[x1][y1] setPositionOnBoard:x1:y1];
173 board[x2][y2] = swap;
174 [board[x2][y2] setPositionOnBoard:x2:y2];
175 sx1 = x1; sx2 = x2; sy1 = y1; sy2 = y2;
180 [self swap:sx1:sy1 and:sx2:sy2];
183 - (BOOL) testForThreeAt:(int) x :(int) y
186 int bonus, linebonus, scorePerGem;
187 float scorebubble_x = -1.0;
188 float scorebubble_y = -1.0;
190 int gemtype = [board[x][y] gemType];
191 tx = x; ty = y; cx = x; cy = y;
193 if ([board[x][y] state] == GEMSTATE_FADING) result = YES;
194 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
195 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
201 scorePerGem = (cx-tx)*5;
202 for (i = tx; i <= cx; i++)
204 linebonus+= scorePerGem;
206 for (j=7; j>y; j--) {
207 if ([board[i][j] state]!= GEMSTATE_FADING) {
208 [board[i][j] shiver]; // MW prepare to fall
212 // to center scorebubble ...
213 scorebubble_x = tx + (cx-tx)/2.0;
219 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
220 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
226 scorePerGem = (cy-ty)*5;
227 for (i = ty; i <= cy; i++)
229 linebonus += scorePerGem;
232 for (j=7; j>cy; j--) {
233 if ([board[x][j] state]!= GEMSTATE_FADING) {
234 [board[x][j] shiver]; // MW prepare to fall
237 // to center scorebubble ...
238 if (scorebubble_x < 0) // only if one hasn't been placed already ! (for T and L shapes)
241 scorebubble_y = ty + (cy-ty)/2.0;
243 else // select the original gem position
259 [scoreBubbles addObject:[ScoreBubble scoreWithValue:bonus*bonusMultiplier
260 At:NSMakePoint(scorebubble_x*48+24, scorebubble_y*48+24)
263 score += bonus * bonusMultiplier;
267 - (BOOL) finalTestForThreeAt:(int) x :(int) y
271 int gemtype = [board[x][y] gemType];
272 tx = x; ty = y; cx = x; cy = y;
274 if ([board[x][y] state] == GEMSTATE_FADING) return YES;
276 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
277 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
282 for (i = tx; i <= cx; i++)
286 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
287 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
292 for (i = ty; i <= cy; i++)
299 - (BOOL) checkForThreeAt:(int) x :(int) y
302 int gemtype = [board[x][y] gemType];
303 tx = x; ty = y; cx = x; cy = y;
304 while ((tx > 0)&&([board[tx-1][y] gemType]==gemtype)) tx = tx-1;
305 while ((cx < 7)&&([board[cx+1][y] gemType]==gemtype)) cx = cx+1;
308 while ((ty > 0)&&([board[x][ty-1] gemType]==gemtype)) ty = ty-1;
309 while ((cy < 7)&&([board[x][cy+1] gemType]==gemtype)) cy = cy+1;
315 - (BOOL) checkBoardForThrees
319 // CASCADE BONUS increase
322 for (i = 0; i < 8; i++)
323 for (j = 0; j < 8; j++)
324 if ([board[i][j] state]!=GEMSTATE_FADING)
325 result = result | [self testForThreeAt:i:j];
326 // CASCADE BONUS check for reset
327 if (!result) cascade = 1;
332 - (void) showAllBoardMoves
334 // test every possible move
338 for (j = 0; j < 8; j++)
339 for (i = 0; i < 7; i++)
341 [self swap:i:j and:i+1:j];
342 [self finalTestForThreeAt:i:j];
343 [self finalTestForThreeAt:i+1:j];
348 for (i = 0; i < 8; i++)
349 for (j = 0; j < 7; j++)
351 [self swap:i:j and:i:j+1];
352 [self finalTestForThreeAt:i:j];
353 [self finalTestForThreeAt:i:j+1];
357 // over the entire board, set the animationtime for the marked gems higher
358 for (i = 0; i < 8; i++)
359 for (j = 0; j < 8; j++)
361 if ([board[i][j] state] == GEMSTATE_FADING)
364 [board[i][j] setAnimationCounter:1];
373 - (BOOL) boardHasMoves
375 // test every possible move
379 for (j = 0; j < 8; j++)
380 for (i = 0; i < 7; i++)
382 [self swap:i:j and:i+1:j];
383 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i+1:j];
394 for (i = 0; i < 8; i++)
395 for (j = 0; j < 7; j++)
397 [self swap:i:j and:i:j+1];
398 result = [self checkForThreeAt:i:j] | [self checkForThreeAt:i:j+1];
410 - (void) removeFadedGemsAndReorganiseWithImagesFrom:(NSArray *) imageArray
413 for (i = 0; i < 8; i++)
418 // let non-faded gems fall into place
419 for (j = 0; j < 8; j++)
421 if ([board[i][j] state] != GEMSTATE_FADING)
423 column[y] = board[i][j];
424 if ([board[i][j] positionOnScreen].y > y*48)
431 // transfer faded gems to top of column
432 for (j = 0; j < 8; j++)
434 if ([board[i][j] state] == GEMSTATE_FADING)
437 int r = (rand() % 7);
438 [board[i][j] setGemType:r];
439 [board[i][j] setImage:[imageArray objectAtIndex:r]];
441 column[y] = board[i][j];
442 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
449 // OK, shuffling all done - reorganise column
450 for (j = 0; j < 8; j++)
452 board[i][j] = column[j];
453 [board[i][j] setPositionOnBoard:i:j];
458 - (void) removeFadedGemsAndReorganiseWithSpritesFrom:(NSArray *) spriteArray
461 for (i = 0; i < 8; i++)
466 // let non-faded gems fall into place
467 for (j = 0; j < 8; j++)
469 if ([board[i][j] state] != GEMSTATE_FADING)
471 column[y] = board[i][j];
472 if ([board[i][j] positionOnScreen].y > y*48)
479 // transfer faded gems to top of column
480 for (j = 0; j < 8; j++)
482 if ([board[i][j] state] == GEMSTATE_FADING)
485 int r = (rand() % 7);
486 [board[i][j] setGemType:r];
487 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
489 column[y] = board[i][j];
490 [board[i][j] setPositionOnScreen:i*48:(7+fades)*48];
497 // OK, shuffling all done - reorganise column
498 for (j = 0; j < 8; j++)
500 board[i][j] = column[j];
501 [board[i][j] setPositionOnBoard:i:j];
509 for (i = 0; i < 8; i++)
510 for (j = 0; j < 8; j++)
517 if (!muted) [[NSSound soundNamed:@"yes"] play];
518 for (i = 0; i < 8; i++)
519 for (j = 0; j < 8; j++)
523 - (void) explodeGameOver
526 if (!muted) [[NSSound soundNamed:@"explosion"] play];
528 for (i = 0; i < 8; i++)
529 for (j = 0; j < 8; j++)
532 [self showAllBoardMoves]; // does a delayed eruption
535 - (void) wholeNewGameWithImagesFrom:(NSArray *) imageArray
538 srand([[NSDate date] timeIntervalSince1970]); // seed by time
539 for (i = 0; i < 8; i++)
540 for (j = 0; j < 8; j++)
542 //int r = (rand() % 3)*2+((i+j)%2);
543 int r = [self randomGemTypeAt:i:j];
544 [board[i][j] setGemType:r];
545 [board[i][j] setImage:[imageArray objectAtIndex:r]];
546 [board[i][j] setPositionOnBoard:i:j];
547 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
555 - (void) wholeNewGameWithSpritesFrom:(NSArray *) spriteArray
558 srand([[NSDate date] timeIntervalSince1970]); // seed by time
559 for (i = 0; i < 8; i++)
560 for (j = 0; j < 8; j++)
562 //int r = (rand() % 3)*2+((i+j)%2);
563 int r = [self randomGemTypeAt:i:j];
564 [board[i][j] setGemType:r];
565 [board[i][j] setSprite:[spriteArray objectAtIndex:r]];
566 [board[i][j] setPositionOnBoard:i:j];
567 [board[i][j] setPositionOnScreen:i*48:(15-j)*48];
575 - (NSPoint) hintPoint
577 return NSMakePoint(hintx*48,hinty*48);
580 - (float) collectGemsFaded
582 float result = (float)gemsFaded;
592 - (int) bonusMultiplier
594 return bonusMultiplier;
597 - (void) increaseBonusMultiplier