1/* 2 * LapisPuzzleView.m 3 4 * Copyright 2004-2011 The Free Software Foundation 5 * 6 * Copyright (C) 2004 Banlu Kemiyatorn. 7 * July 19, 2004 8 * Written by Banlu Kemiyatorn <object at gmail dot com> 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 19 * You should have received a copy of the GNU Library General Public 20 * License along with this library; if not, write to the Free 21 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. 22 */ 23 24#import "LapisPuzzleView.h" 25#import "LPController.h" 26#include <math.h> 27 28static float _grid_height; 29 30#define MATCH_COLOR(a,b) ((a == b)) 31 32@implementation LPUnit 33 34- (id) description 35{ 36 return [NSString stringWithFormat:@"<%@: %p %d>",[self className], self, _color]; 37} 38 39+ (void) setGridHeight:(float)points 40{ 41 _grid_height = points; 42} 43 44- (id) initWithOwner:(id <LPUnitOwner>)owner 45 color:(LPUnitColorType)color 46{ 47 alpha = 1.0; 48 __owner = owner; 49 _color = color; 50 _isBlowing = NO; 51 return self; 52} 53 54- (void) setOwner:(id <LPUnitOwner>)owner 55{ 56 __owner = owner; 57} 58 59- (float) alpha 60{ 61 return alpha; 62} 63 64- (void) setAlpha:(float)a 65{ 66 if (a < 0) 67 a = 0; 68 alpha = a; 69} 70 71- (LPUnitColorType) unitColor 72{ 73 return _color; 74} 75 76- (void) setUnitColor:(LPUnitColorType)color 77{ 78 _color = color; 79} 80 81- (int) rows 82{ 83 return 0; 84} 85 86- (int) columns 87{ 88 return 0; 89} 90 91- (BOOL) hasPartAtX:(int)x 92 Y:(int)y 93{ 94 return NO; 95} 96 97- (void) fallToBottom 98{ 99 while ([self moveInDir:LP_MOVE_DOWN]); 100} 101 102- (BOOL) isBlowing 103{ 104 return _isBlowing; 105} 106 107- (void) softBlow 108{ 109 _isBlowing = YES; 110} 111 112- (void) blow 113{ 114 int unit_x, unit_y, unit_rows, unit_columns; 115 int i; 116 id m; 117 118 if (_isBlowing) 119 { 120 return; 121 } 122 123 _isBlowing = YES; 124 125 unit_x = [self X]; 126 unit_y = [self Y]; 127 unit_rows = [self rows]; 128 unit_columns = [self columns]; 129 130 for (i = 0; i < unit_columns; i++) 131 { 132 m = [__owner getUnitAtX:unit_x + i 133 Y:unit_y - 1]; 134 135 if (m && (MATCH_COLOR([m unitColor], _color) || [m isMemberOfClass:[LPStoneUnit class]])) 136 { 137 [m blow]; 138 } 139 140 m = [__owner getUnitAtX:unit_x + i 141 Y:unit_y + unit_rows]; 142 if (m && (MATCH_COLOR([m unitColor], _color) || [m isMemberOfClass:[LPStoneUnit class]])) 143 { 144 [m blow]; 145 } 146 147 } 148 149 for (i = 0; i < unit_rows; i++) 150 { 151 m = [__owner getUnitAtX:unit_x - 1 152 Y:unit_y + i]; 153 if (m && (MATCH_COLOR([m unitColor], _color) || [m isMemberOfClass:[LPStoneUnit class]])) 154 { 155 [m blow]; 156 } 157 158 m = [__owner getUnitAtX:unit_x + unit_columns 159 Y:unit_y + i]; 160 if (m && (MATCH_COLOR([m unitColor], _color) || [m isMemberOfClass:[LPStoneUnit class]])) 161 { 162 [m blow]; 163 } 164 165 } 166} 167 168/** subclass responsibility **/ 169 170- (BOOL) moveInDir:(LPDirType)dir 171{ 172 return NO; 173} 174 175- (BOOL) rMoveX:(int)rx Y:(int)ry 176{ 177 return NO; 178} 179 180- (void) changePhase 181{ 182} 183 184- (int) X 185{ 186 return 0; 187} 188 189- (int) Y 190{ 191 return 0; 192} 193 194- (float) phase 195{ 196 return 0.0; 197} 198 199- (void) explode 200{ 201} 202 203- (void) draw 204{ 205} 206 207- (void) round 208{ 209} 210 211- (void) setX:(unsigned int)x Y:(unsigned int)y 212{ 213} 214 215- (BOOL) canMoveInDir:(LPDirType)dir 216{ 217 return NO; 218} 219 220- (BOOL) canRMoveX:(int)rx Y:(int)ry 221{ 222 return NO; 223} 224 225@end 226 227@implementation LPStoneUnit; 228- (id) initWithOwner:(id <LPUnitOwner>)owner 229 color:(LPUnitColorType)color 230 X:(int)x 231 Y:(int)y 232{ 233 _count = 5; 234 235 return [super initWithOwner:owner 236 color:color 237 X:x 238 Y:y]; 239} 240 241- (int) count 242{ 243 return _count; 244} 245 246- (void) countDown 247{ 248 _count--; 249} 250 251 252- (void) draw 253{ 254 int i; 255 NSColor *tcolor; 256 NSMutableAttributedString *str; 257 NSSize strSize; 258 NSSize gz = [__owner gridSize]; 259 float border = gz.width/6; 260 261 [super draw]; 262 263 PSsetrgbcolor(0.7,0.7,0.7); 264 PSsetalpha(alpha); 265 PSrectfill(_x * gz.width , _y *gz.height, _columns * gz.width, _rows * gz.height); 266 PSsetrgbcolor(1,1,1); 267 268 PSsetalpha(alpha/3); 269 PSsetlinewidth(0); 270 PSmoveto(_x * gz.width, _y * gz.height); 271 PSlineto(_x * gz.width + gz.width/4, _y * gz.height + gz.width/4); 272 PSlineto(_x * gz.width + gz.width/4, (_y+_rows) * gz.height - gz.width/4); 273 PSlineto(_x * gz.width, (_y+_rows) * gz.height); 274 PSfill(); 275 276 PSsetalpha(alpha); 277 PSsetlinewidth(0); 278 PSmoveto(_x * gz.width, (_y+_rows) * gz.height); 279 PSlineto(_x * gz.width + gz.width/4, (_y+_rows) * gz.height - gz.width/4); 280 PSlineto((_x+_columns) * gz.width - gz.width/4, (_y+_rows) * gz.height - gz.width/4); 281 PSlineto((_x+_columns) * gz.width, (_y+_rows) * gz.height); 282 PSfill(); 283 284 for (i = 0; i <_rows; i+=2) 285 { 286 PSgsave(); 287 PSsetlinecap(1); 288 PSsetalpha(alpha/10); 289 PSsetlinewidth(_columns * border * 4); 290 PSrectclip(_x * gz.width + gz.width/4, _y *gz.height + gz.height/4, _columns * gz.width - gz.width/2, _rows * gz.height - gz.height/2); 291 292 PSmoveto(_x * gz.width, (_y + i) * gz.height); 293 PSlineto((_x + _columns) * gz.width, (_y + i + _columns) * gz.height); 294 PSstroke(); 295 PSgrestore(); 296 } 297 298 for (i = 0; i <_rows; i++) 299 { 300 PSgsave(); 301 PSsetlinecap(1); 302 PSsetlinewidth(_columns * border * 2); 303 PSrectclip(_x * gz.width + gz.width/4, _y *gz.height + gz.height/4, _columns * gz.width - gz.width/2, _rows * gz.height - gz.height/2); 304 305 PSsetalpha(alpha/4); 306 PSmoveto(_x * gz.width, (_y + i*4) * gz.height + (i + _rows) * 10); 307 PSlineto((_x + _columns) * gz.width, (_y + i*4 + _columns) * gz.height + (i + _rows) * 10); 308 PSstroke(); 309 PSgrestore(); 310 } 311 312 PSsetrgbcolor(0.3,0.3,0.3); 313 314 PSsetalpha(alpha/2); 315 PSsetlinewidth(0); 316 PSmoveto(_x * gz.width, _y * gz.height); 317 PSlineto(_x * gz.width + gz.width/4, _y * gz.height + gz.width/4); 318 PSlineto((_x+_columns) * gz.width - gz.width/4, _y * gz.height + gz.width/4); 319 PSlineto((_x+_columns) * gz.width, _y * gz.height); 320 PSfill(); 321 322 PSsetalpha(alpha/3); 323 PSsetlinewidth(0); 324 PSmoveto((_x+_columns) * gz.width, _y * gz.height); 325 PSlineto((_x+_columns) * gz.width - gz.width/4, _y * gz.height + gz.width/4); 326 PSlineto((_x+_columns) * gz.width - gz.width/4, (_y+_rows) * gz.height - gz.width/4); 327 PSlineto((_x+_columns) * gz.width, (_y+_rows) * gz.height); 328 PSfill(); 329 330 331 /****/ 332 333 PSsetrgbcolor(0,0,0); 334 PSsetalpha(0.8); 335 PSrectfill(_x * gz.width + gz.width/8, _y *gz.height + gz.height/8, gz.width - gz.width/4, gz.height - gz.height/4); 336 337 switch (_color) 338 { 339 case LP_COLOR_YELLOW: 340 tcolor = [NSColor yellowColor]; 341 break; 342 case LP_COLOR_GREEN: 343 tcolor = [NSColor greenColor]; 344 break; 345 case LP_COLOR_RED: 346 tcolor = [NSColor redColor]; 347 break; 348 case LP_COLOR_BLUE: 349 tcolor = [NSColor blueColor]; 350 break; 351 default: 352 tcolor = [NSColor grayColor]; 353 } 354 355 str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%d",_count]]; 356 [str addAttribute:NSForegroundColorAttributeName 357 value:tcolor 358 range:NSMakeRange(0,1)]; 359 [str addAttribute:NSFontAttributeName 360 value:[NSFont boldSystemFontOfSize:gz.height/1.5] 361 range:NSMakeRange(0,1)]; 362 strSize = [str size]; 363 364 PSsetalpha(alpha); 365 [str drawAtPoint:NSMakePoint(_x * gz.width + gz.width/2 - strSize.width/2, _y * gz.height + gz.height/2 - strSize.height/2)]; 366 367} 368 369- (void) blow 370{ 371 _isBlowing = YES; 372} 373@end 374 375@implementation LPSparkerUnit 376- (void) spark 377{ 378 int unit_x, unit_y, unit_rows, unit_columns; 379 int i; 380 id m; 381 382 unit_x = [self X]; 383 unit_y = [self Y]; 384 unit_rows = [self rows]; 385 unit_columns = [self columns]; 386 387 for (i = 0; i < unit_columns; i++) 388 { 389 m = [__owner getUnitAtX:unit_x + i 390 Y:unit_y - 1]; 391 392 if (m && MATCH_COLOR([m unitColor],_color) && ![m isMemberOfClass:[LPStoneUnit class]]) 393 { 394 [self blow]; 395 } 396 397 m = [__owner getUnitAtX:unit_x + i 398 Y:unit_y + unit_rows]; 399 if (m && MATCH_COLOR([m unitColor],_color) && ![m isMemberOfClass:[LPStoneUnit class]]) 400 { 401 [self blow]; 402 } 403 404 } 405 406 for (i = 0; i < unit_rows; i++) 407 { 408 m = [__owner getUnitAtX:unit_x - 1 409 Y:unit_y + i]; 410 if (m && MATCH_COLOR([m unitColor], _color) && ![m isMemberOfClass:[LPStoneUnit class]]) 411 { 412 [self blow]; 413 } 414 415 m = [__owner getUnitAtX:unit_x + unit_columns 416 Y:unit_y + i]; 417 if (m && MATCH_COLOR([m unitColor], _color) && ![m isMemberOfClass:[LPStoneUnit class]]) 418 { 419 [self blow]; 420 } 421 422 } 423} 424 425- (void) draw 426{ 427 NSSize gz = [__owner gridSize]; 428 float border = gz.width/7; 429 430 switch (_color) 431 { 432 case LP_COLOR_BLUE: 433 PSsetrgbcolor(0,0,0.5); 434 break; 435 case LP_COLOR_RED: 436 PSsetrgbcolor(0.5,0,0); 437 break; 438 case LP_COLOR_GREEN: 439 PSsetrgbcolor(0,0.5,0); 440 break; 441 case LP_COLOR_YELLOW: 442 PSsetrgbcolor(0.5,0.5,0); 443 break; 444 default: 445 PSsetrgbcolor(0.5,0.5,0.5); 446 break; 447 } 448 PSmoveto(_x * gz.width + gz.width/2, _y * gz.height); 449 PSlineto(_x * gz.width + border, _y * gz.height + border); 450 PSlineto(_x * gz.width, _y * gz.height + gz.height/2); 451 PSlineto(_x * gz.width + border, (_y+1) * gz.height - border); 452 PSlineto(_x * gz.width + gz.width/2, (_y+1) * gz.height); 453 PSlineto((_x+1) * gz.width - border, (_y+1) * gz.height - border); 454 PSlineto((_x+1) * gz.width, _y * gz.height + gz.height/2); 455 PSlineto((_x+1) * gz.width - border, _y * gz.height + border); 456 457 PSclosepath(); 458 PSsetalpha(alpha); 459 PSfill(); 460 461 switch (_color) 462 { 463 case LP_COLOR_BLUE: 464 PSsetrgbcolor(0,0,1.0-z); 465 break; 466 case LP_COLOR_RED: 467 PSsetrgbcolor(1.0-z,0,0); 468 break; 469 case LP_COLOR_GREEN: 470 PSsetrgbcolor(0,1.0-z,0); 471 break; 472 case LP_COLOR_YELLOW: 473 PSsetrgbcolor(1.0-z,1.0-z,0); 474 break; 475 default: 476 PSsetrgbcolor(1.0-z,1.0-z,1.0-z); 477 break; 478 } 479 480 PSmoveto(_x * gz.width + gz.width/2, _y * gz.height); 481 PSrlineto(gz.width/2, gz.height/2); 482 PSrlineto(-gz.width/2, gz.height/2); 483 PSrlineto(-gz.width/2, -gz.height/2); 484 PSclosepath(); 485 PSsetalpha(alpha); 486 PSfill(); 487 488 switch (_color) 489 { 490 case LP_COLOR_BLUE: 491 PSsetrgbcolor(0,0,0.5+z); 492 break; 493 case LP_COLOR_RED: 494 PSsetrgbcolor(0.5+z,0,0); 495 break; 496 case LP_COLOR_GREEN: 497 PSsetrgbcolor(0,0.5+z,0); 498 break; 499 case LP_COLOR_YELLOW: 500 PSsetrgbcolor(0.5+z,0.5+z,0); 501 break; 502 default: 503 PSsetrgbcolor(0.5+z,0.5+z,0.5+z); 504 break; 505 } 506 507 PSsetalpha(alpha/1.5); 508 PSrectfill(_x * gz.width + border , _y *gz.height + border, _columns * gz.width - border*2, _rows * gz.height - border*2); 509 510 511 512 switch (_color) 513 { 514 case LP_COLOR_BLUE: 515 PSsetrgbcolor(0,0,1.0-z); 516 break; 517 case LP_COLOR_RED: 518 PSsetrgbcolor(1.0-z,0,0); 519 break; 520 case LP_COLOR_GREEN: 521 PSsetrgbcolor(0,1.0-z,0); 522 break; 523 case LP_COLOR_YELLOW: 524 PSsetrgbcolor(1.0-z,1.0-z,0); 525 break; 526 default: 527 PSsetrgbcolor(1.0-z,1.0-z,1.0-z); 528 break; 529 } 530 531 532 PSsetalpha(alpha/2); 533 PSmoveto(_x * gz.width + gz.width/2, _y * gz.height); 534 PSlineto(_x * gz.width + border, _y * gz.height + border); 535 PSlineto(_x * gz.width, _y * gz.height + gz.height/2); 536 PSlineto(_x * gz.width + border, (_y+1) * gz.height - border); 537 PSlineto(_x * gz.width + gz.width/2, (_y+1) * gz.height); 538 PSlineto((_x+1) * gz.width - border, (_y+1) * gz.height - border); 539 PSlineto((_x+1) * gz.width, _y * gz.height + gz.height/2); 540 PSlineto((_x+1) * gz.width - border, _y * gz.height + border); 541 542 PSlineto(_x * gz.width + gz.width/2, _y * gz.height); 543 PSlineto((_x+1) * gz.width, _y * gz.height + gz.height/2); 544 PSlineto(_x * gz.width + gz.width/2, (_y+1) * gz.height); 545 PSlineto(_x * gz.width, _y * gz.height + gz.height/2); 546 547 PSclosepath(); 548 PSfill(); 549} 550 551@end 552 553@implementation LPJewelUnit 554- (id) initWithOwner:(id <LPUnitOwner>)owner 555 color:(LPUnitColorType)color 556 X:(int)x 557 Y:(int)y 558{ 559 [super initWithOwner:owner 560 color:color]; 561 562 _x = x; 563 _y = y; 564 _rows = 1; 565 _columns = 1; 566 z = random()%5; 567 z/= 10; 568 [self changePhase]; 569 return self; 570} 571 572- (float) phase 573{ 574 return z; 575} 576 577- (void) changePhase 578{ 579 z += 0.1; 580 if (z > 0.5) 581 { 582 z = 0; 583 } 584} 585 586- (int) rows 587{ 588 return _rows; 589} 590 591- (int) columns 592{ 593 return _columns; 594} 595 596- (int) X 597{ 598 return _x; 599} 600 601- (int) Y 602{ 603 return _y; 604} 605 606- (void) draw 607{ 608 NSSize gz = [__owner gridSize]; 609 float border = gz.width/6; 610 611 switch (_color) 612 { 613 case LP_COLOR_BLUE: 614 PSsetrgbcolor(0,0,0.7); 615 break; 616 case LP_COLOR_RED: 617 PSsetrgbcolor(0.7,0,0); 618 break; 619 case LP_COLOR_GREEN: 620 PSsetrgbcolor(0,0.7,0); 621 break; 622 case LP_COLOR_YELLOW: 623 PSsetrgbcolor(0.7,0.7,0); 624 break; 625 default: 626 PSsetrgbcolor(0.7,0.7,0.7); 627 break; 628 } 629 PSsetalpha(alpha); 630 PSrectfill(_x * gz.width , _y *gz.height, _columns * gz.width, _rows * gz.height); 631 switch (_color) 632 { 633 case LP_COLOR_BLUE: 634 PSsetrgbcolor(0,0,0.6); 635 break; 636 case LP_COLOR_RED: 637 PSsetrgbcolor(0.6,0,0); 638 break; 639 case LP_COLOR_GREEN: 640 PSsetrgbcolor(0,0.6,0); 641 break; 642 case LP_COLOR_YELLOW: 643 PSsetrgbcolor(0.6,0.6,0); 644 break; 645 default: 646 PSsetrgbcolor(0.6,0.6,0.6); 647 break; 648 } 649 PSsetalpha(alpha); 650 //PSrectfill(_x * gz.width + border, _y *gz.height + border, _columns * gz.width - 2*border, _rows * gz.height - 2*border); 651 652 switch (_color) 653 { 654 case LP_COLOR_BLUE: 655 PSsetrgbcolor(0,0.5,1); 656 break; 657 case LP_COLOR_RED: 658 PSsetrgbcolor(1,0.2,0.2); 659 break; 660 case LP_COLOR_GREEN: 661 PSsetrgbcolor(0.5,1,0); 662 break; 663 case LP_COLOR_YELLOW: 664 PSsetrgbcolor(1,1,0.0); 665 break; 666 default: 667 PSsetrgbcolor(1,1,1); 668 break; 669 } 670 671 PSsetalpha(alpha/3); 672 PSsetlinewidth(0); 673 PSmoveto(_x * gz.width, _y * gz.height); 674 PSlineto(_x * gz.width + gz.width/4, _y * gz.height + gz.width/4); 675 PSlineto(_x * gz.width + gz.width/4, (_y+_rows) * gz.height - gz.width/4); 676 PSlineto(_x * gz.width, (_y+_rows) * gz.height); 677 PSfill(); 678 679 PSsetalpha(alpha); 680 PSsetlinewidth(0); 681 PSmoveto(_x * gz.width, (_y+_rows) * gz.height); 682 PSlineto(_x * gz.width + gz.width/4, (_y+_rows) * gz.height - gz.width/4); 683 PSlineto((_x+_columns) * gz.width - gz.width/4, (_y+_rows) * gz.height - gz.width/4); 684 PSlineto((_x+_columns) * gz.width, (_y+_rows) * gz.height); 685 PSfill(); 686 687 if (_rows > 1) 688 { 689 int i; 690 for (i = 0; i <_rows; i+=2) 691 { 692 PSgsave(); 693 PSsetlinecap(1); 694 PSsetalpha(alpha/10); 695 PSsetlinewidth(_columns * border * 4); 696 PSrectclip(_x * gz.width + gz.width/4, _y *gz.height + gz.height/4, _columns * gz.width - gz.width/2, _rows * gz.height - gz.height/2); 697 698 PSmoveto(_x * gz.width, (_y + i) * gz.height); 699 PSlineto((_x + _columns) * gz.width, (_y + i + _columns) * gz.height); 700 PSstroke(); 701 PSgrestore(); 702 } 703 704 for (i = 0; i <_rows; i++) 705 { 706 PSgsave(); 707 PSsetlinecap(1); 708 PSsetlinewidth(_columns * border * 2); 709 PSrectclip(_x * gz.width + gz.width/4, _y *gz.height + gz.height/4, _columns * gz.width - gz.width/2, _rows * gz.height - gz.height/2); 710 711 PSsetalpha(alpha/4); 712 PSmoveto(_x * gz.width, (_y + i*4) * gz.height + (i + _rows) * 10); 713 PSlineto((_x + _columns) * gz.width, (_y + i*4 + _columns) * gz.height + (i + _rows) * 10); 714 PSstroke(); 715 PSgrestore(); 716 } 717 } 718 719 switch (_color) 720 { 721 case LP_COLOR_BLUE: 722 PSsetrgbcolor(0,0,0.3); 723 break; 724 case LP_COLOR_RED: 725 PSsetrgbcolor(0.3,0,0); 726 break; 727 case LP_COLOR_GREEN: 728 PSsetrgbcolor(0,0.3,0); 729 break; 730 case LP_COLOR_YELLOW: 731 PSsetrgbcolor(0.3,0.3,0); 732 break; 733 default: 734 PSsetrgbcolor(0.3,0.3,0.3); 735 break; 736 } 737 738 739 PSsetalpha(alpha/2); 740 PSsetlinewidth(0); 741 PSmoveto(_x * gz.width, _y * gz.height); 742 PSlineto(_x * gz.width + gz.width/4, _y * gz.height + gz.width/4); 743 PSlineto((_x+_columns) * gz.width - gz.width/4, _y * gz.height + gz.width/4); 744 PSlineto((_x+_columns) * gz.width, _y * gz.height); 745 PSfill(); 746 747 PSsetalpha(alpha/3); 748 PSsetlinewidth(0); 749 PSmoveto((_x+_columns) * gz.width, _y * gz.height); 750 PSlineto((_x+_columns) * gz.width - gz.width/4, _y * gz.height + gz.width/4); 751 PSlineto((_x+_columns) * gz.width - gz.width/4, (_y+_rows) * gz.height - gz.width/4); 752 PSlineto((_x+_columns) * gz.width, (_y+_rows) * gz.height); 753 PSfill(); 754 755} 756 757- (BOOL) canRMoveX:(int)rx 758 Y:(int)ry 759{ 760 id en; 761 LPUnit* unit; 762 763 int cx,cy,i,j; 764 765 cx = _x + rx; 766 cy = _y + ry; 767 768 if (cx < 0 || cx > 5 || cy < 0) 769 { 770 return NO; 771 } 772 773 en = [[__owner allUnits] objectEnumerator]; 774 while ((unit = [en nextObject])) 775 { 776 if (unit == self) 777 { 778 continue; 779 } 780 for (j = 0; j < _rows; j++) 781 { 782 for (i = 0; i < _columns; i++) 783 { 784 if ([unit hasPartAtX:cx+i 785 Y:cy+j]) 786 { 787 return NO; 788 } 789 } 790 } 791 } 792 793 return YES; 794} 795 796- (BOOL) canMoveInDir:(LPDirType)dir 797{ 798 int cx,cy; 799 800 switch(dir) 801 { 802 case LP_MOVE_LEFT: 803 if (_x == 0) 804 { 805 return NO; 806 } 807 cx = -1; 808 cy = 0; 809 break; 810 case LP_MOVE_DOWN: 811 if (_y == 0) 812 { 813 return NO; 814 } 815 cx = 0; 816 cy = -1; 817 break; 818 case LP_MOVE_RIGHT: 819 if (_x == 5) 820 { 821 return NO; 822 } 823 cx = 1; 824 cy = 0; 825 break; 826 case LP_MOVE_UP: 827 /* no check for upper border */ 828 cx = 0; 829 cy = 1; 830 break; 831 default: 832 NSAssert(0, @"Unreachable"); 833 return NO; 834 break; 835 } 836 837 return [self canRMoveX:cx Y:cy]; 838} 839 840- (BOOL) rMoveX:(int)rx 841 Y:(int)ry 842{ 843 if (![self canRMoveX:rx 844 Y:ry]) 845 { 846 return NO; 847 } 848 _x += rx; 849 _y += ry; 850 851 return YES; 852} 853 854- (BOOL) moveInDir:(LPDirType)dir 855{ 856 if (![self canMoveInDir:dir]) 857 { 858 return NO; 859 } 860 switch(dir) 861 { 862 case LP_MOVE_DOWN: 863 _y--; 864 break; 865 case LP_MOVE_LEFT: 866 _x--; 867 break; 868 case LP_MOVE_UP: 869 _y++; 870 break; 871 case LP_MOVE_RIGHT: 872 _x++; 873 break; 874 default: 875 NSAssert(0, @"Unreachable"); 876 break; 877 878 } 879 return YES; 880} 881 882- (BOOL) hasPartAtX:(int)x 883 Y:(int)y 884{ 885 if (x >= _x && y >= _y && x < (_x + _columns) && y < (_y + _rows)) 886 { 887 return YES; 888 } 889 return NO; 890} 891 892- (void) addRows:(int)r 893{ 894 _rows += r; 895} 896 897- (void) addColumns:(int)c 898{ 899 _columns += c; 900} 901@end 902 903@implementation LPGroupUnit 904 905- (id) initWithOwner:(id <LPUnitOwner>)owner 906 atoms:(NSArray *)unitList 907{ 908 __owner = owner; 909 ASSIGN(_units, unitList); 910 _laydir = LP_MOVE_DOWN; 911 return self; 912} 913 914- (NSSize) gridSize 915{ 916 return [__owner gridSize]; 917} 918 919- (NSArray *) allUnits 920{ 921 NSMutableArray *array = [NSMutableArray arrayWithArray:[__owner allUnits]]; 922 [array removeObject:self]; 923 return array; 924} 925 926- (NSArray *) atoms 927{ 928 return _units; 929} 930 931- (id) getUnitAtX:(int)x 932 Y:(int)y 933{ 934 exit(0); 935 // NYI 936} 937 938- (void) rotateCCW 939{ 940 id move = [_units objectAtIndex:0]; 941 id base = [_units objectAtIndex:1]; 942 943 switch(_laydir) 944 { 945 case LP_MOVE_DOWN: 946 if ([move rMoveX:-1 947 Y:-1]) 948 { 949 _laydir = LP_MOVE_LEFT; 950 } 951 else if ([base canRMoveX:1 Y:0]) 952 { 953 [base rMoveX:1 Y:0]; 954 [move rMoveX:0 Y:-1]; 955 _laydir = LP_MOVE_LEFT; 956 } 957 break; 958 case LP_MOVE_LEFT: 959 if ([move rMoveX:1 960 Y:-1]) 961 { 962 _laydir = LP_MOVE_UP; 963 } 964 break; 965 case LP_MOVE_UP: 966 if ([move rMoveX:1 967 Y:1]) 968 { 969 _laydir = LP_MOVE_RIGHT; 970 } 971 else if ([base canRMoveX:-1 Y:0]) 972 { 973 [base rMoveX:-1 Y:0]; 974 [move rMoveX:0 Y:1]; 975 _laydir = LP_MOVE_RIGHT; 976 } 977 break; 978 case LP_MOVE_RIGHT: 979 if ([move rMoveX:-1 980 Y:1]) 981 { 982 _laydir = LP_MOVE_DOWN; 983 } 984 break; 985 default: 986 NSAssert(0, @"Unreachable"); 987 break; 988 } 989 990} 991 992- (void) rotateCW 993{ 994 id move = [_units objectAtIndex:0]; 995 id base = [_units objectAtIndex:1]; 996 997 switch(_laydir) 998 { 999 case LP_MOVE_DOWN: 1000 if ([move rMoveX:1 // should physically block rotation? 1001 Y:-1]) 1002 { 1003 _laydir = LP_MOVE_RIGHT; 1004 } 1005 else if ([base canRMoveX:-1 Y:0]) 1006 { 1007 [base rMoveX:-1 Y:0]; 1008 [move rMoveX:0 Y:-1]; 1009 _laydir = LP_MOVE_RIGHT; 1010 } 1011 break; 1012 case LP_MOVE_RIGHT: 1013 if ([move rMoveX:-1 1014 Y:-1]) 1015 { 1016 _laydir = LP_MOVE_UP; 1017 } 1018 break; 1019 case LP_MOVE_UP: 1020 if ([move rMoveX:-1 1021 Y:1]) 1022 { 1023 _laydir = LP_MOVE_LEFT; 1024 } 1025 else if ([base canRMoveX:1 Y:0]) 1026 { 1027 [base rMoveX:1 Y:0]; 1028 [move rMoveX:0 Y:1]; 1029 _laydir = LP_MOVE_LEFT; 1030 } 1031 break; 1032 case LP_MOVE_LEFT: 1033 if ([move rMoveX:1 1034 Y:1]) 1035 { 1036 _laydir = LP_MOVE_DOWN; 1037 } 1038 break; 1039 default: 1040 NSAssert(0, @"Unreachable"); 1041 break; 1042 } 1043 1044} 1045 1046- (void) changePhase 1047{ 1048 id en; 1049 LPUnit* unit; 1050 1051 en = [_units objectEnumerator]; 1052 while ((unit = [en nextObject])) 1053 { 1054 [unit changePhase]; 1055 } 1056} 1057 1058- (void) draw 1059{ 1060 id en; 1061 LPUnit* unit; 1062 1063 en = [_units objectEnumerator]; 1064 while ((unit = [en nextObject])) 1065 { 1066 [unit draw]; 1067 } 1068} 1069 1070- (int) X 1071{ 1072 id en; 1073 LPUnit* unit; 1074 float mX; 1075 mX = 5; 1076 1077 en = [_units objectEnumerator]; 1078 while ((unit = [en nextObject])) 1079 { 1080 if ([unit X] < mX) 1081 { 1082 mX = [unit X]; 1083 } 1084 } 1085 return mX; 1086} 1087 1088- (int) Y 1089{ 1090 return 0; 1091} 1092 1093- (void) dealloc 1094{ 1095 RELEASE(_units); 1096 [super dealloc]; 1097} 1098 1099- (BOOL) hasPartAtX:(int)x 1100 Y:(int)y 1101{ 1102 id en; 1103 LPUnit* unit; 1104 1105 en = [_units objectEnumerator]; 1106 while ((unit = [en nextObject])) 1107 { 1108 if ([unit hasPartAtX:x 1109 Y:y]) 1110 { 1111 return YES; 1112 } 1113 } 1114 return NO; 1115} 1116 1117- (BOOL) moveInDir:(LPDirType)dir 1118{ 1119 id en; 1120 LPUnit* unit; 1121 1122 en = [_units objectEnumerator]; 1123 while ((unit = [en nextObject])) 1124 { 1125 if([unit canMoveInDir:dir] == NO) 1126 { 1127 return NO; 1128 } 1129 } 1130 1131 en = [_units objectEnumerator]; 1132 while ((unit = [en nextObject])) 1133 { 1134 [unit moveInDir:dir]; 1135 } 1136 return YES; 1137} 1138 1139- (BOOL) canMoveInDir:(LPDirType)dir 1140{ 1141 id en; 1142 LPUnit* unit; 1143 1144 en = [_units objectEnumerator]; 1145 while ((unit = [en nextObject])) 1146 { 1147 if([unit canMoveInDir:dir] == NO) 1148 { 1149 return NO; 1150 } 1151 } 1152 return YES; 1153} 1154 1155- (BOOL) canRMoveX:(int)rx 1156 Y:(int)ry 1157{ 1158 id en; 1159 LPUnit* unit; 1160 1161 en = [_units objectEnumerator]; 1162 while ((unit = [en nextObject])) 1163 { 1164 if([unit canRMoveX:rx Y:ry] == NO) 1165 { 1166 return NO; 1167 } 1168 } 1169 return YES; 1170} 1171 1172- (BOOL) rMoveX:(int)rx 1173 Y:(int)ry 1174{ 1175 id en; 1176 LPUnit* unit; 1177 1178 en = [_units objectEnumerator]; 1179 while ((unit = [en nextObject])) 1180 { 1181 if([unit canRMoveX:rx Y:ry] == NO) 1182 { 1183 return NO; 1184 } 1185 } 1186 1187 en = [_units objectEnumerator]; 1188 while ((unit = [en nextObject])) 1189 { 1190 [unit rMoveX:rx Y:ry]; 1191 } 1192 return YES; 1193} 1194 1195@end 1196 1197@implementation LapisPuzzleView 1198 1199static LPUnitColorType _random_unit_color() 1200{ 1201 return random()%LP_COLOR_ALL; 1202} 1203 1204static LPUnit * _random_unit(id owner, int x, int y, BOOL diamond) 1205{ 1206 LPUnit* unit; 1207 if (random()%20 < 6) 1208 { 1209 if (random()%10 == 1 && diamond) 1210 { 1211 unit = [[LPSparkerUnit alloc] initWithOwner:owner 1212 color:LP_COLOR_ALL 1213 X:x 1214 Y:y]; 1215 } 1216 else 1217 { 1218 1219 unit = [[LPSparkerUnit alloc] initWithOwner:owner 1220 color:_random_unit_color() 1221 X:x 1222 Y:y]; 1223 } 1224 } 1225 else 1226 { 1227 unit = [[LPJewelUnit alloc] initWithOwner:owner 1228 color:_random_unit_color() 1229 X:x 1230 Y:y]; 1231 } 1232 return AUTORELEASE(unit); 1233} 1234 1235 1236- (NSSize) gridSize 1237{ 1238 return NSMakeSize( 1239 NSWidth(_bounds)/(_numberOfColumns * _stepsInUnit), 1240 NSHeight(_bounds)/(((float)_numberOfRows + 0.3) * _stepsInUnit) 1241 ); 1242} 1243 1244- (void) awakeFromNib 1245{ 1246 chain = 0; 1247 trip = 0; 1248 chaintrip = 0; 1249 _gameOver = NO; 1250 _numberOfRows = 13; 1251 _numberOfColumns = 6; 1252 1253 _stepsInUnit = 1; 1254 _stepHeight = NSHeight(_frame)/((float)_numberOfRows + 0.3); 1255 _stepWidth = NSWidth(_frame)/_numberOfColumns; 1256 1257 _units = [[NSMutableArray alloc] init]; 1258 1259 _blowing = [[NSMutableSet alloc] init]; 1260 1261} 1262 1263- (void) setFrame:(NSRect)r 1264{ 1265 [super setFrame:r]; 1266} 1267 1268- (void) setBackgroundImage:(NSImage *)image 1269{ 1270 ASSIGN(_background, image); 1271} 1272 1273- (void) gameOver 1274{ 1275 _gameOver = YES; 1276} 1277 1278- (void) round 1279{ 1280 id en; 1281 LPUnit* unit; 1282 1283 if (chain) 1284 { 1285 [self fallEmDown]; 1286 [self packCell]; 1287 [self blowIt]; 1288 if (chain == 0) 1289 { 1290 [self runStone]; 1291 } 1292 [self setNeedsDisplay:YES]; 1293 return; 1294 } 1295 1296 _lockControl = NO; 1297 1298 if (__currentUnit == nil) 1299 { 1300 if (!_gameOver) 1301 { 1302 [__owner lapisPuzzleView:self 1303 didFinishUnitWithResult:LP_RESULT_REQUEST]; 1304 } 1305 } 1306 1307 if(![__currentUnit moveInDir:LP_MOVE_DOWN]) 1308 { 1309 if (__currentUnit) 1310 { 1311 /* replace timer stone with jewel */ 1312 NSMutableArray *ar; 1313 1314 _lockControl = YES; 1315 ar = [NSMutableArray array]; 1316 en = [_units objectEnumerator]; 1317 while ((unit = [en nextObject])) 1318 { 1319 if ([unit isMemberOfClass:[LPStoneUnit class]]) 1320 { 1321 [(LPStoneUnit *)unit countDown]; 1322 if ([(LPStoneUnit *)unit count] == 0) 1323 { 1324 [ar addObject:unit]; 1325 } 1326 } 1327 } 1328 1329 en = [ar objectEnumerator]; 1330 while ((unit = [en nextObject])) 1331 { 1332 id new; 1333 new = [[LPJewelUnit alloc] initWithOwner:self 1334 color:[unit unitColor] 1335 X:[unit X] 1336 Y:[unit Y]]; 1337 [_units removeObject:unit]; 1338 [_units addObject:new]; 1339 [new release]; 1340 } 1341 1342 1343 en = [[__currentUnit atoms] objectEnumerator]; 1344 while ((unit = [en nextObject])) 1345 { 1346 [_units addObject:unit]; 1347 [unit setOwner:self]; 1348 [unit fallToBottom]; 1349 } 1350 1351 1352 [_units removeObject:__currentUnit]; 1353 __currentUnit = nil; 1354 } 1355 1356 [self packCell]; 1357 [self blowIt]; 1358 if (chain == 0) 1359 { 1360 [self runStone]; 1361 } 1362 1363 1364 } 1365 1366 [self setNeedsDisplay:YES]; 1367} 1368 1369- (void) runStone 1370{ 1371 LPUnit* unit; 1372 /* run stone */ 1373 int yy,xx; 1374 1375 if (stone > 0) 1376 { 1377 [(LPController *)__owner player:self processStone:stone]; 1378 } 1379 1380 yy = 13, xx = 0; 1381 while (stone > 0) 1382 { 1383 unit = nil; 1384 while (unit == nil) 1385 { 1386 while (unit == nil) 1387 { 1388 if ([self getUnitAtX:xx Y:yy] == nil) 1389 { 1390 unit = [[LPStoneUnit alloc] initWithOwner:self 1391 color:_random_unit_color() 1392 X:xx 1393 Y:yy]; 1394 [_units addObject:unit]; 1395 [unit fallToBottom]; 1396 RELEASE(unit); 1397 } 1398 xx++; 1399 if (xx > 5) 1400 { 1401 xx = 0; 1402 break; 1403 } 1404 } 1405 yy++; 1406 } 1407 stone--; 1408 } 1409} 1410 1411- (id) getUnitAtX:(int)x 1412 Y:(int)y 1413{ 1414 id en; 1415 LPUnit* unit; 1416 1417 en = [_units objectEnumerator]; 1418 while ((unit = [en nextObject])) 1419 { 1420 if ([unit hasPartAtX:x 1421 Y:y]) 1422 { 1423 return unit; 1424 } 1425 } 1426 1427 return nil; 1428} 1429 1430- (void) fallEmDown 1431{ 1432 id en; 1433 LPUnit* unit; 1434 BOOL moving; 1435 1436 /* fall em down */ 1437 do 1438 { 1439 moving = NO; 1440 en = [_units objectEnumerator]; 1441 while ((unit = [en nextObject])) 1442 { 1443 if ([unit moveInDir:LP_MOVE_DOWN]) 1444 { 1445 moving = YES; 1446 } 1447 } 1448 } while (moving); 1449 1450} 1451 1452- (void) packCell 1453{ 1454 id en; 1455 LPJewelUnit* unit; 1456 int i,j; 1457 BOOL merge; 1458 1459 1460 id m1,m2,m3; 1461 LPUnitColorType color; 1462 1463 if (_gameOver) 1464 { 1465 return; 1466 } 1467 1468 /* pack bigger cell */ 1469 for (i = 0; i < 12; i++) 1470 { 1471 for (j = 0; j < 5; j++) 1472 { 1473 unit = [self getUnitAtX:j 1474 Y:i]; 1475 if (unit && [unit rows] == 1 && [unit isMemberOfClass:[LPJewelUnit class]]) 1476 { 1477 color = [unit unitColor]; 1478 if ((m1 = [self getUnitAtX:j+1 Y:i]) && 1479 [m1 unitColor] == color && 1480 [m1 rows] == 1 && 1481 [m1 isMemberOfClass:[LPJewelUnit class]] && 1482 (m2 = [self getUnitAtX:j Y:i+1]) && 1483 [m2 unitColor] == color && 1484 [m2 rows] == 1 && 1485 [m2 isMemberOfClass:[LPJewelUnit class]] && 1486 (m3 = [self getUnitAtX:j+1 Y:i+1]) && 1487 [m3 unitColor] == color && 1488 [m3 rows] == 1 && 1489 [m3 isMemberOfClass:[LPJewelUnit class]] 1490 ) 1491 { 1492 [unit addRows:1]; 1493 [unit addColumns:1]; 1494 [_units removeObject:m1]; 1495 [_units removeObject:m2]; 1496 [_units removeObject:m3]; 1497 } 1498 } 1499 } 1500 } 1501 1502 do 1503 { 1504 merge = NO; 1505 en = [_units objectEnumerator]; 1506 while ((unit = [en nextObject])) 1507 { 1508 int unit_x, unit_y, unit_rows, unit_columns; 1509 LPUnitColorType color; 1510 1511 unit_rows = [unit rows]; 1512 1513 if (unit_rows >= 2) 1514 { 1515 NSMutableArray *ar = [NSMutableArray array]; 1516 1517 color = [unit unitColor]; 1518 unit_x = [unit X]; 1519 unit_y = [unit Y]; 1520 unit_columns = [unit columns]; 1521 1522 1523 m1 = [self getUnitAtX:unit_x + unit_columns 1524 Y:unit_y]; 1525 1526 /* check horizontal axis */ 1527 if (m1 && [m1 isMemberOfClass:[LPJewelUnit class]] && [m1 Y] == unit_y && [m1 rows] == unit_rows && [m1 unitColor] == color) 1528 { 1529 merge = YES; 1530 [unit addColumns:[m1 columns]]; 1531 [_units removeObject:m1]; 1532 break; 1533 } 1534 1535 m1 = [self getUnitAtX:unit_x 1536 Y:unit_y + unit_rows]; 1537 1538 /* check vertical axis */ 1539 if (m1 && [m1 isMemberOfClass:[LPJewelUnit class]] && [m1 X] == unit_x && [m1 columns] == unit_columns && [m1 unitColor] == color) 1540 { 1541 merge = YES; 1542 [unit addRows:[m1 rows]]; 1543 [_units removeObject:m1]; 1544 break; 1545 } 1546 1547 1548 /* check right side */ 1549 for (i = 0; i < unit_rows; i++) 1550 { 1551 m1 = [self getUnitAtX:unit_x + unit_columns 1552 Y:unit_y + i]; 1553 if (m1 == nil || ![m1 isMemberOfClass:[LPJewelUnit class]] || [m1 rows] > 1 || [m1 unitColor]!=color) 1554 { 1555 break; 1556 } 1557 [ar addObject:m1]; 1558 } 1559 if ([ar count] == unit_rows) 1560 { 1561 id en2, unit2; 1562 1563 merge = YES; 1564 en2 = [ar objectEnumerator]; 1565 while ((unit2 = [en2 nextObject])) 1566 { 1567 [_units removeObject:unit2]; 1568 } 1569 [unit addColumns:1]; 1570 break; 1571 } 1572 1573 /* check left side */ 1574 ar = [NSMutableArray array]; 1575 for (i = 0; i < unit_rows; i++) 1576 { 1577 m1 = [self getUnitAtX:unit_x - 1 1578 Y:unit_y + i]; 1579 if (m1 == nil || ![m1 isMemberOfClass:[LPJewelUnit class]] || [m1 rows] > 1 || [m1 unitColor]!=color) 1580 { 1581 break; 1582 } 1583 [ar addObject:m1]; 1584 } 1585 if ([ar count] == unit_rows) 1586 { 1587 id en2, unit2; 1588 1589 merge = YES; 1590 en2 = [ar objectEnumerator]; 1591 while ((unit2 = [en2 nextObject])) 1592 { 1593 [_units removeObject:unit2]; 1594 } 1595 [unit addColumns:1]; 1596 [unit moveInDir:LP_MOVE_LEFT]; 1597 break; 1598 } 1599 1600 /* check top side */ 1601 ar = [NSMutableArray array]; 1602 for (i = 0; i < unit_columns; i++) 1603 { 1604 m1 = [self getUnitAtX:unit_x + i 1605 Y:unit_y + unit_rows]; 1606 if (m1 == nil || ![m1 isMemberOfClass:[LPJewelUnit class]] || [m1 rows] > 1 || [m1 unitColor]!=color) 1607 { 1608 break; 1609 } 1610 [ar addObject:m1]; 1611 } 1612 if ([ar count] == unit_columns) 1613 { 1614 id en2, unit2; 1615 1616 merge = YES; 1617 en2 = [ar objectEnumerator]; 1618 while ((unit2 = [en2 nextObject])) 1619 { 1620 [_units removeObject:unit2]; 1621 } 1622 [unit addRows:1]; 1623 break; 1624 } 1625 1626 /* check bottom side */ 1627 ar = [NSMutableArray array]; 1628 for (i = 0; i < unit_columns; i++) 1629 { 1630 m1 = [self getUnitAtX:unit_x + i 1631 Y:unit_y - 1]; 1632 if (m1 == nil || ![m1 isMemberOfClass:[LPJewelUnit class]] || [m1 rows] > 1 || [m1 unitColor]!=color) 1633 { 1634 break; 1635 } 1636 [ar addObject:m1]; 1637 } 1638 if ([ar count] == unit_columns) 1639 { 1640 id en2, unit2; 1641 1642 merge = YES; 1643 en2 = [ar objectEnumerator]; 1644 while ((unit2 = [en2 nextObject])) 1645 { 1646 [_units removeObject:unit2]; 1647 } 1648 [unit addRows:1]; 1649 [unit moveInDir:LP_MOVE_DOWN]; 1650 break; 1651 } 1652 1653 } 1654 } 1655 } while(merge); 1656} 1657 1658- (void) blowIt 1659{ 1660 id en; 1661 LPUnit *unit; 1662 int i; 1663 1664 LPUnit *all = nil; 1665 1666 if (_gameOver) 1667 { 1668 return; 1669 } 1670 1671 en = [_units objectEnumerator]; 1672 while ((unit = [en nextObject])) 1673 { 1674 if ([unit isMemberOfClass:[LPSparkerUnit class]]) 1675 { 1676 if ([unit unitColor] == LP_COLOR_ALL) 1677 { 1678 [unit blow]; 1679 all = [self getUnitAtX:[unit X] 1680 Y:[unit Y] - 1]; 1681 } 1682 else [(LPSparkerUnit *)unit spark]; 1683 } 1684 } 1685 1686 if (all) 1687 { 1688 en = [_units objectEnumerator]; 1689 while ((unit = [en nextObject])) 1690 { 1691 if ([unit unitColor] == [all unitColor]) 1692 { 1693 [unit softBlow]; 1694 } 1695 } 1696 } 1697 1698 i = 0; 1699 en = [_units objectEnumerator]; 1700 while ((unit = [en nextObject])) 1701 { 1702 if ([unit isBlowing]) 1703 { 1704 [_blowing addObject:unit]; 1705 i++; 1706 } 1707 } 1708 1709 if (i) 1710 { 1711// NSLog(@"blow blocks %d",i); 1712 } 1713 stone -= (i/4) * chain + chain>1?chain:0; 1714 1715 en = [_blowing objectEnumerator]; 1716 while ((unit = [en nextObject])) 1717 { 1718 if ([_units containsObject:unit]) 1719 { 1720 if ([unit rows] > 1) 1721 { 1722 stone -= [unit rows] * 2 * [unit columns] * (chain + 1); 1723 } 1724 [_units removeObject:unit]; 1725 } 1726 } 1727 1728 if (i) 1729 { 1730 chain ++; 1731 if (chain >= 2) 1732 { 1733 stone -= chain; 1734 } 1735 chaintrip = chain * 2; 1736 if (chaintrip > 8) 1737 { 1738 chaintrip = 8; 1739 } 1740 if (chain > maxchain) 1741 { 1742 maxchain = chain; 1743 } 1744 } 1745 else 1746 { 1747 chain = 0; 1748 1749 if (stone < 0) 1750 { 1751 [__owner player:self addStoneToOp:-stone]; 1752 stone = 0; 1753 } 1754 } 1755 1756#if 0 1757 if (stone < 0) 1758 { 1759// NSLog(@"%@ sends %d stones",self,-stone); 1760 [__owner player:self addStoneToOp:-stone]; 1761 stone = 0; 1762 } 1763#endif 1764} 1765 1766- (void) restart 1767{ 1768 id en; 1769 LPUnit * unit; 1770 [self gameOver]; 1771 if (__currentUnit) 1772 { 1773 [_units removeObject:__currentUnit]; 1774 __currentUnit = nil; 1775 } 1776 en = [_units objectEnumerator]; 1777 while ((unit = [en nextObject])) 1778 { 1779 [unit blow]; 1780 } 1781 1782 en = [_units objectEnumerator]; 1783 while ((unit = [en nextObject])) 1784 { 1785 if ([unit isBlowing]) 1786 { 1787 [_blowing addObject:unit]; 1788 } 1789 } 1790 1791 en = [_blowing objectEnumerator]; 1792 while ((unit = [en nextObject])) 1793 { 1794 [_units removeObject:unit]; 1795 } 1796 1797 _gameOver = NO; 1798 stone = 0; 1799 trip = 0; 1800 chaintrip = 0; 1801} 1802 1803- (void) refresh 1804{ 1805 id en; 1806 LPUnit *unit; 1807 1808 NSMutableArray *ar; 1809 1810 ar = [NSMutableArray array]; 1811 1812 if (trip) 1813 { 1814 trip--; 1815 } 1816 if (chaintrip) 1817 { 1818 chaintrip--; 1819 if (chaintrip == 0) 1820 { 1821 maxchain = 0; 1822 } 1823 } 1824 1825 en = [_units objectEnumerator]; 1826 while ((unit = [en nextObject])) 1827 { 1828 if (!_gameOver) 1829 { 1830 [unit changePhase]; 1831 } 1832 } 1833 1834 if (_gameOver) 1835 { 1836 int cc,xx,yy; 1837 LPUnit* unit; 1838 cc=0; 1839 1840 for (yy = 13; yy >= 0 && cc < 8; yy--) 1841 for (xx = 5; xx >= 0; xx--) 1842 { 1843 unit = [self getUnitAtX:xx 1844 Y:yy]; 1845 1846 if (unit && [unit unitColor] != LP_COLOR_ALL) 1847 { 1848 [unit setUnitColor:LP_COLOR_ALL]; 1849 cc++; 1850 } 1851 } 1852 } 1853 else 1854 { 1855 en = [_blowing objectEnumerator]; 1856 while ((unit = [en nextObject])) 1857 { 1858 [unit setAlpha:[unit alpha]-0.2]; 1859 if ([unit alpha] < 0.2) 1860 { 1861 [ar addObject:unit]; 1862 } 1863 } 1864 en = [ar objectEnumerator]; 1865 while ((unit = [en nextObject])) 1866 { 1867 [_blowing removeObject:unit]; 1868 } 1869 } 1870 1871 [self setNeedsDisplay:YES]; 1872} 1873 1874- (void) addStone:(int)num 1875{ 1876 stone += num; 1877 if (stone > 0) 1878 { 1879 trip = 8; 1880 } 1881} 1882 1883- (void) addUnit:(id)newUnit 1884{ 1885 [_units addObject:newUnit]; 1886 1887 __currentUnit = newUnit; 1888 1889 if (![__currentUnit canMoveInDir:LP_MOVE_DOWN]) 1890 { 1891 [_units removeObject:__currentUnit]; 1892 __currentUnit = nil; 1893 [self gameOver]; 1894 [__owner lapisPuzzleView:self 1895 didFinishUnitWithResult:LP_RESULT_GAMEOVER]; 1896 1897 } 1898 [self setNeedsDisplay:YES]; 1899} 1900 1901- (void) addJewelUnit 1902{ 1903 /* 1904 id newUnit = [LPGroupUnit alloc]; 1905 [newUnit initWithOwner:self 1906 atoms:[NSArray arrayWithObjects: 1907 _random_unit(newUnit,3,14), 1908 _random_unit(newUnit,3,13),nil]]; 1909 1910 [self addUnit:AUTORELEASE(newUnit)]; 1911 */ 1912} 1913 1914- (void) drawRect:(NSRect)r 1915{ 1916 int i; 1917 id en; 1918 LPUnit *unit; 1919 1920 /* 1921 [_background compositeToPoint:NSZeroPoint 1922 operation:NSCompositeCopy]; 1923 */ 1924 1925 PSsetrgbcolor(0,0,0); 1926 PSsetalpha(1.0); // 0.7 1927 PSrectfill(0,0,NSWidth(_bounds),NSHeight(_bounds)); 1928 1929 PSsetrgbcolor(1,1,1); 1930 PSsetalpha(0.1); 1931 PSmoveto(0,0); 1932 for (i = 0; i < _numberOfRows; i++) 1933 { 1934 PSrlineto(NSWidth(_bounds), 0); 1935 PSrmoveto(-NSWidth(_bounds), _stepHeight); 1936 } 1937 PSstroke(); 1938 1939 PSmoveto(0,0); 1940 for (i = 0; i < _numberOfColumns; i++) 1941 { 1942 PSrlineto(0,NSHeight(_bounds)); 1943 PSrmoveto(_stepWidth,-NSHeight(_bounds)); 1944 } 1945 PSstroke(); 1946 1947 en = [_blowing objectEnumerator]; 1948 while ((unit = [en nextObject])) 1949 { 1950 float p = [(LPJewelUnit *)unit phase] * 50; 1951 p = p - 12; 1952 PSgsave(); 1953 PStranslate((1 - [unit alpha]) * p, (1 - [unit alpha]) * -p); 1954 [unit draw]; 1955 PSgrestore(); 1956 } 1957 1958 1959 { 1960 int cc,xx,yy; 1961 LPUnit* unit; 1962 NSMutableSet *set = [NSMutableSet setWithCapacity:70]; 1963 cc=0; 1964 1965 for (yy = 13; yy >= 0 && cc < 8; yy--) 1966 for (xx = 5; xx >= 0; xx--) 1967 { 1968 unit = [self getUnitAtX:xx 1969 Y:yy]; 1970 if (unit != nil) 1971 { 1972 [set addObject:unit]; 1973 } 1974 } 1975 [set makeObjectsPerform:@selector(draw)]; 1976 } 1977 1978 PSgsave(); 1979 PSinitclip(); 1980 1981 PSsetrgbcolor(0,0,0); 1982 PSsetalpha(0.3); 1983 PSrectfill(0, _stepHeight * 12, _stepWidth * 3, _stepHeight); 1984 PSrectfill(_stepWidth * 4, _stepHeight * 12, _stepWidth * 2, _stepHeight); 1985 1986 PSsetalpha(0.5); 1987 PSsetrgbcolor(0.7,0.7,0.7); 1988 PSsetlinewidth(4); 1989 PSrectstroke(0, _stepHeight * 12, _stepWidth * 3, _stepHeight); 1990 PSrectstroke(_stepWidth * 4, _stepHeight * 12, _stepWidth * 2, _stepHeight); 1991 PSmoveto(0,NSHeight(_bounds)); 1992 PSlineto(0,0); 1993 PSlineto(NSWidth(_bounds),0); 1994 PSlineto(NSWidth(_bounds),NSHeight(_bounds)); 1995 PSstroke(); 1996 1997 /****/ 1998 1999 PSsetalpha(1); 2000 PSsetrgbcolor(0,0,0); 2001 PSsetlinewidth(2); 2002 PSrectstroke(0, _stepHeight * 12, _stepWidth * 3, _stepHeight); 2003 PSrectstroke(_stepWidth * 4, _stepHeight * 12, _stepWidth * 2, _stepHeight); 2004 PSmoveto(0,NSHeight(_bounds)); 2005 PSlineto(0,0); 2006 PSlineto(NSWidth(_bounds),0); 2007 PSlineto(NSWidth(_bounds),NSHeight(_bounds)); 2008 PSstroke(); 2009 2010 2011 PStranslate(-1,1); 2012 PSsetrgbcolor(0.8,0.8,0.8); 2013 PSsetlinewidth(2); 2014 PSrectstroke(0, _stepHeight * 12, _stepWidth * 3, _stepHeight); 2015 PSrectstroke(_stepWidth * 4, _stepHeight * 12, _stepWidth * 2, _stepHeight); 2016 PSmoveto(0,NSHeight(_bounds)); 2017 PSlineto(0,0); 2018 PSlineto(NSWidth(_bounds),0); 2019 PSlineto(NSWidth(_bounds),NSHeight(_bounds)); 2020 PSstroke(); 2021 PSgrestore(); 2022 2023 if (trip || stone > 0) 2024 { 2025 int istone = stone > 0?stone:0; 2026 NSMutableAttributedString *str; 2027 NSString *s; 2028 NSSize strSize; 2029 NSSize gz = [self gridSize]; 2030 s = [NSString stringWithFormat:@"%d",istone]; 2031 str = [[NSMutableAttributedString alloc] initWithString:s]; 2032 [str addAttribute:NSForegroundColorAttributeName 2033 value:[NSColor redColor] 2034 range:NSMakeRange(0,[s length])]; 2035 [str addAttribute:NSFontAttributeName 2036 value:[NSFont boldSystemFontOfSize:gz.height*1.2] 2037 range:NSMakeRange(0,[s length])]; 2038 strSize = [str size]; 2039 2040 [str drawAtPoint:NSMakePoint(5 * gz.width - strSize.width/2, 12 * gz.height + gz.height/2 - strSize.height/2)]; 2041 RELEASE(str); 2042 } 2043 2044 if (chaintrip%2 == 1 && maxchain > 1) 2045 { 2046 NSMutableAttributedString *str; 2047 NSString *s; 2048 NSSize strSize; 2049 NSSize gz = [self gridSize]; 2050 s = [NSString stringWithFormat:@"%d CHAINS!",maxchain]; 2051 str = [[NSMutableAttributedString alloc] initWithString:s]; 2052 [str addAttribute:NSForegroundColorAttributeName 2053 value:[NSColor yellowColor] 2054 range:NSMakeRange(0,[s length])]; 2055 [str addAttribute:NSFontAttributeName 2056 value:[NSFont boldSystemFontOfSize:gz.height * (maxchain>4?4:maxchain)/4] 2057 range:NSMakeRange(0,[s length])]; 2058 strSize = [str size]; 2059 2060 [str drawAtPoint:NSMakePoint((6 * gz.width / 2) - strSize.width/2, (13 * gz.height / 2) - strSize.height/2)]; 2061 RELEASE(str); 2062 } 2063 2064} 2065 2066- (NSArray *) allUnits 2067{ 2068 return _units; 2069} 2070 2071/*** key ***/ 2072- (BOOL) acceptsFirstResponder 2073{ 2074 return YES; 2075} 2076 2077-(BOOL) performKeyEquivalent: (NSEvent *)event 2078{ 2079 return NO; 2080} 2081 2082- (id) currentUnit 2083{ 2084 return __currentUnit; 2085} 2086 2087-(BOOL) processDir:(LPDirType)dir 2088{ 2089 if (_lockControl) 2090 { 2091 return NO; 2092 } 2093 if (__currentUnit == nil) 2094 { 2095 return NO; 2096 } 2097 switch(dir) 2098 { 2099 case LP_MOVE_DOWN: 2100 return [__currentUnit moveInDir:LP_MOVE_DOWN]; 2101 break; 2102 case LP_MOVE_LEFT: 2103 return [__currentUnit moveInDir:LP_MOVE_LEFT]; 2104 break; 2105 case LP_MOVE_RIGHT: 2106 return [__currentUnit moveInDir:LP_MOVE_RIGHT]; 2107 break; 2108 case LP_MOVE_FALL: 2109 _lockControl = YES; 2110 [__currentUnit fallToBottom]; 2111 break; 2112 case LP_MOVE_CW: 2113 [__currentUnit rotateCW]; 2114 break; 2115 case LP_MOVE_CCW: 2116 [__currentUnit rotateCCW]; 2117 break; 2118 default: 2119 NSAssert(0, @"Unreachable"); 2120 break; 2121 2122 } 2123 2124 [self setNeedsDisplay:YES]; 2125 return YES; 2126} 2127 2128-(void) keyDown: (NSEvent *)event 2129{ 2130//NSLog(@"%d %@",[event keyCode], [event characters]); 2131 2132 switch ([[event characters] characterAtIndex:0]) 2133 { 2134 case 'a': 2135 _useAI = !_useAI; 2136 break; 2137 case ',': 2138 [self processDir:LP_MOVE_CW]; 2139 break; 2140 case '.': 2141 [self processDir:LP_MOVE_CCW]; 2142 break; 2143 case ' ': 2144 [self processDir:LP_MOVE_FALL]; 2145 break; 2146 case NSUpArrowFunctionKey: 2147 [self processDir:LP_MOVE_CCW]; 2148 break; 2149 case NSLeftArrowFunctionKey: 2150 [self processDir:LP_MOVE_LEFT]; 2151 break; 2152 case NSRightArrowFunctionKey: 2153 [self processDir:LP_MOVE_RIGHT]; 2154 break; 2155 case NSDownArrowFunctionKey: 2156 [self processDir:LP_MOVE_DOWN]; 2157 break; 2158 case 'd': 2159 [__owner op:self processDir:LP_MOVE_CW]; 2160 break; 2161 case 'f': 2162 [__owner op:self processDir:LP_MOVE_CCW]; 2163 break; 2164 case 'x': 2165 [__owner op:self processDir:LP_MOVE_LEFT]; 2166 break; 2167 case 'v': 2168 [__owner op:self processDir:LP_MOVE_RIGHT]; 2169 break; 2170 case 'c': 2171 [__owner op:self processDir:LP_MOVE_DOWN]; 2172 break; 2173 default: 2174 break; 2175 } 2176 [self setNeedsDisplay:YES]; 2177} 2178 2179- (void) toggleAI 2180{ 2181 _useAI = !_useAI; 2182} 2183 2184- (BOOL) useAI 2185{ 2186 return _useAI; 2187} 2188 2189@end 2190 2191@implementation LapisNextView 2192- (void) awakeFromNib 2193{ 2194 chain = 0; 2195 trip = 0; 2196 chaintrip = 0; 2197 _gameOver = NO; 2198 _numberOfRows = 2; 2199 _numberOfColumns = 1; 2200 2201 _stepsInUnit = 1; 2202 _stepHeight = NSHeight(_frame)/((float)_numberOfRows); 2203 _stepWidth = NSWidth(_frame)/_numberOfColumns; 2204 2205 _units = [[NSMutableArray alloc] init]; 2206 2207 _blowing = [[NSMutableSet alloc] init]; 2208 2209} 2210 2211- (NSSize) gridSize 2212{ 2213 return NSMakeSize( 2214 NSWidth(_bounds)/(_numberOfColumns * _stepsInUnit), 2215 NSHeight(_bounds)/(((float)_numberOfRows) * _stepsInUnit) 2216 ); 2217} 2218 2219- (void) addJewelUnit 2220{ 2221 id newUnit = [LPGroupUnit alloc]; 2222 newUnit = [newUnit initWithOwner:self 2223 atoms:[NSArray arrayWithObjects: 2224 _random_unit(newUnit,0,10,YES), 2225 _random_unit(newUnit,0,9,NO),nil]]; 2226 2227 [self addUnit:AUTORELEASE(newUnit)]; 2228} 2229 2230- (void) removeUnit:(id)unit 2231{ 2232 [_units removeObject:unit]; 2233} 2234 2235-(void) keyDown: (NSEvent *)event 2236{ 2237} 2238 2239@end 2240