1 /* Copyright (C) 1993, 1992 Nathan Sidwell */ 2 /* RCS $Id: move.c,v 4.3 1993/10/25 12:02:18 nathan Stable $ */ 3 #include "xmris.h" 4 /*{{{ prototypes*/ 5 static VOIDFUNC connect_hole PROTOARG((CELL *)); 6 static int apple_hole PROTOARG((APPLE *, CELL *)); 7 static VOIDFUNC munch_back 8 PROTOARG((int, int, unsigned, unsigned, int, int, SPRITE CONST *)); 9 static VOIDFUNC munch_edge_above PROTOARG((CELL *, int, int, unsigned)); 10 static VOIDFUNC munch_edge_below PROTOARG((CELL *, int, int, int, unsigned)); 11 static VOIDFUNC munch_edge_left PROTOARG((CELL *, int, int, unsigned)); 12 static VOIDFUNC munch_edge_right PROTOARG((CELL *, int, int, unsigned)); 13 /*}}}*/ 14 /*{{{ int apple_hole(aptr, cptr)*/ 15 static int apple_hole 16 FUNCARG((aptr, cptr), 17 APPLE *aptr 18 ARGSEP CELL *cptr 19 ) 20 /* 21 * An apple has fallen, this makes the hole it 22 * leaves behind in the hedge, but only in the board table 23 * remember to get it drawn too. 24 */ 25 { 26 int offset; 27 28 offset = aptr->offset.x / VEL_X * VEL_X; 29 if(offset < 0) 30 { 31 int max; 32 33 max = cptr[0].depths[2] < cptr[CELL_STRIDE].depths[2] ? 34 cptr[CELL_STRIDE].depths[2] : cptr[0].depths[2]; 35 if(max >= offset) 36 offset = max + VEL_X; 37 if(offset < 0) 38 { 39 assert(offset > -(CELL_WIDTH + GAP_WIDTH)); 40 cptr[CELL_STRIDE].holes[0] = cptr[0].holes[2] = offset; 41 cptr[CELL_STRIDE - 1].holes[1] = 42 cptr[-1].holes[3] = CELL_WIDTH + GAP_WIDTH + offset; 43 } 44 else 45 offset = 0; 46 } 47 else if(offset > 0) 48 { 49 int min; 50 51 min = cptr[0].depths[3] > cptr[CELL_STRIDE].depths[3] ? 52 cptr[CELL_STRIDE].depths[3] : cptr[0].depths[3]; 53 if(min <= offset) 54 offset = min - VEL_X; 55 if(offset > 0) 56 { 57 assert(offset < (CELL_WIDTH + GAP_WIDTH)); 58 cptr[CELL_STRIDE].holes[1] = cptr[0].holes[3] = offset; 59 cptr[CELL_STRIDE + 1].holes[0] = 60 cptr[1].holes[2] = -(CELL_WIDTH + GAP_WIDTH) + offset; 61 } 62 else 63 offset = 0; 64 } 65 return offset; 66 } 67 /*}}}*/ 68 /*{{{ void back_sprite(ix, flag, x, y)*/ 69 extern VOIDFUNC back_sprite 70 FUNCARG((ix, flag, x, y), 71 unsigned ix 72 ARGSEP unsigned flag 73 ARGSEP int x 74 ARGSEP int y 75 ) 76 /* 77 * copy a sprite onto the background 78 */ 79 { 80 SPRITE CONST *sptr; 81 82 sptr = &sprites[ix]; 83 if(display.background != COLOUR_ZERO || flag) 84 XCopyArea(display.display, sptr->mask, display.back, GCN(GC_MASK), 85 0, 0, sptr->size.x, sptr->size.y, x, y); 86 XCopyArea(display.display, sptr->image, display.back, GCN(GC_OR), 87 0, 0, sptr->size.x, sptr->size.y, x, y); 88 return; 89 } 90 /*}}}*/ 91 /*{{{ unsigned choose_direction(valid)*/ 92 extern unsigned choose_direction 93 FUNCARG((valid), 94 unsigned valid 95 ) 96 /* 97 * pick a direction at chaotic from the valid ones 98 */ 99 { 100 unsigned choices; 101 unsigned temp; 102 unsigned choice; 103 104 assert(valid && !(valid & ~0xF)); 105 for(choices = 0, temp = valid; temp; choices++) 106 temp ^= temp & -temp; 107 if(choices == 1) 108 choice = 0; 109 else if(choices == 3) 110 choice = chaotic() % 3; 111 else 112 choice = chaotic() & (choices - 1); 113 do 114 { 115 temp = valid & -valid; 116 valid ^= temp; 117 } 118 while(choice--); 119 assert(temp); 120 for(valid = 0; !(temp & 1); valid++) 121 temp >>= 1; 122 return valid; 123 } 124 /*}}}*/ 125 /*{{{ void connect_hole(cptr)*/ 126 static VOIDFUNC connect_hole 127 FUNCARG((cptr), 128 CELL *cptr 129 ) 130 /* 131 * connect the current cell up to its neighbours 132 */ 133 { 134 cptr[0].visit = 1; 135 if(cptr[-CELL_STRIDE].depths[1] >= GAP_HEIGHT) 136 { 137 cptr[0].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 138 cptr[-CELL_STRIDE].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 139 } 140 if(cptr[CELL_STRIDE].depths[0] <= -GAP_HEIGHT) 141 { 142 cptr[0].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 143 cptr[CELL_STRIDE].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 144 } 145 if(cptr[-1].depths[3] >= GAP_WIDTH) 146 { 147 cptr[0].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 148 cptr[-1].depths[3] = CELL_WIDTH + GAP_WIDTH; 149 } 150 if(cptr[1].depths[2] <= -GAP_WIDTH) 151 { 152 cptr[0].depths[3] = CELL_WIDTH + GAP_WIDTH; 153 cptr[1].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 154 } 155 return; 156 } 157 /*}}}*/ 158 /*{{{ CELL *drop_apple(aptr, cptr)*/ 159 extern CELL *drop_apple 160 FUNCARG((aptr, cptr), 161 APPLE *aptr 162 ARGSEP CELL *cptr 163 ) 164 /* 165 * deals with apples which break through to the cell below 166 * the apple has already been moved to the new coordinate 167 * returns NULL if we stay in the same cell, or a pointer 168 * to the new cell 169 */ 170 { 171 CELL *new; 172 COORD pixel; 173 CELL *cherry; 174 175 update.set = 0; 176 pixel.x = aptr->pixel.x - aptr->offset.x; 177 pixel.y = aptr->pixel.y - aptr->offset.y; 178 cherry = NULL; 179 if(aptr->offset.y <= cptr[0].depths[1]) 180 { 181 if(INRANGE(aptr->offset.y, 1, APPLE_VEL_Y + 1)) 182 { 183 int offset; 184 185 offset = apple_hole(aptr, cptr); 186 if(offset) 187 munch_edge_below(cptr, pixel.x + offset, pixel.y, offset, 0); 188 } 189 new = NULL; 190 } 191 else if(!cptr[0].visit) 192 { 193 aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT; 194 aptr->cell.y += 1; 195 pixel.y += CELL_HEIGHT + GAP_HEIGHT; 196 new = cptr + CELL_STRIDE; 197 } 198 else if(cptr[CELL_STRIDE].visit) 199 /*{{{ break through below*/ 200 { 201 int offset; 202 203 offset = apple_hole(aptr, cptr); 204 /*{{{ munch*/ 205 { 206 munch_edge_below(cptr, pixel.x + offset, pixel.y, 207 offset, (unsigned)!offset); 208 if(!offset && !cptr[0].depths[2]) 209 { 210 munch_back(0, 0, EDGE_WIDTH >> 1, GAP_HEIGHT, 211 pixel.x + (CELL_WIDTH >> 1) - (EDGE_WIDTH >> 1), 212 pixel.y + CELL_HEIGHT - GAP_HEIGHT, 213 &sprites[SPRITE_EDGE_BASE + 1]); 214 cherry = cptr; 215 } 216 if(!offset && !cptr[0].depths[3]) 217 { 218 munch_back(EDGE_WIDTH >> 1, 0, 219 EDGE_WIDTH >> 1, GAP_HEIGHT, 220 pixel.x + (CELL_WIDTH >> 1), 221 pixel.y + CELL_HEIGHT - GAP_HEIGHT, 222 &sprites[SPRITE_EDGE_BASE + 1]); 223 cherry = cptr; 224 } 225 } 226 /*}}}*/ 227 aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT; 228 aptr->cell.y += 1; 229 pixel.y += CELL_HEIGHT + GAP_HEIGHT; 230 global.broken = 1; 231 new = cptr + CELL_STRIDE; 232 if(!offset) 233 { 234 cptr[0].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 235 cptr[CELL_STRIDE].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 236 } 237 } 238 /*}}}*/ 239 else if(cptr[0].depths[1] - cptr[CELL_STRIDE * 2].depths[0] >= 240 CELL_HEIGHT + GAP_HEIGHT) 241 /*{{{ breakthrough 2 below*/ 242 { 243 aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT; 244 aptr->cell.y += 1; 245 pixel.y += CELL_HEIGHT + GAP_HEIGHT; 246 global.broken = 1; 247 cptr[CELL_STRIDE].visit = 1; 248 cptr[0].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 249 cptr[CELL_STRIDE].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 250 cptr[CELL_STRIDE].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 251 cptr[CELL_STRIDE * 2].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 252 if(cptr[CELL_STRIDE - 1].depths[3]) 253 { 254 cptr[CELL_STRIDE].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 255 cptr[CELL_STRIDE - 1].depths[3] = CELL_WIDTH + GAP_WIDTH; 256 } 257 if(cptr[CELL_STRIDE + 1].depths[2]) 258 { 259 cptr[CELL_STRIDE].depths[3] = CELL_WIDTH + GAP_WIDTH; 260 cptr[CELL_STRIDE + 1].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 261 } 262 munch_hole(cptr + CELL_STRIDE, pixel.x, pixel.y); 263 cherry = new = cptr + CELL_STRIDE; 264 } 265 /*}}}*/ 266 else 267 new = NULL; 268 if(cherry && cherry->sprite) 269 back_sprite(new->sprite, 0, pixel.x, pixel.y); 270 if(update.set) 271 { 272 bounding_box(aptr->pixel.x, aptr->pixel.y, CELL_WIDTH, CELL_HEIGHT); 273 bounding_box(aptr->old_pixel.x, aptr->old_pixel.y, 274 CELL_WIDTH, CELL_HEIGHT); 275 aptr->back = 1; 276 add_background(update.tl.x, update.tl.y, 277 (unsigned)(update.br.x - update.tl.x), 278 (unsigned)(update.br.y - update.tl.y)); 279 } 280 return new; 281 } 282 /*}}}*/ 283 /*{{{ CELL *move_diamond(mptr, cptr)*/ 284 extern CELL *move_diamond 285 FUNCARG((mptr, cptr), 286 MONSTER *mptr 287 ARGSEP CELL *cptr 288 ) 289 /* 290 * move the diamond downwards, munching away as we go 291 */ 292 { 293 CELL *nptr; 294 295 assert(!mptr->offset.x && mptr->dir == 1); 296 nptr = NULL; 297 if(mptr->offset.y) 298 /* EMPTY */; 299 else if(cptr[CELL_STRIDE].visit || cptr[CELL_STRIDE].sprite || 300 mptr->cell.y == CELLS_DOWN - 1) 301 mptr->stop = 1; 302 else 303 { 304 APPLE *aptr; 305 unsigned count; 306 307 for(aptr = apple.list, count = apple.apples; count--; aptr++) 308 if(aptr->state < 3 && aptr->cell.y == mptr->cell.y + 1 && 309 INRANGE(aptr->pixel.x - mptr->pixel.x, 310 VEL_X - CELL_WIDTH + 1, CELL_WIDTH - VEL_X)) 311 { 312 mptr->stop = 1; 313 break; 314 } 315 } 316 if(!mptr->stop) 317 { 318 mptr->offset.y += DIAMOND_VEL_Y; 319 mptr->pixel.y += DIAMOND_VEL_Y; 320 update.set = 0; 321 cptr[0].depths[1] = mptr->offset.y; 322 if(mptr->offset.y < CELL_HEIGHT + GAP_HEIGHT) 323 { 324 munch_back(0, CELL_HEIGHT - DIAMOND_VEL_Y - INTERNAL_HEIGHT, 325 EDGE_WIDTH, DIAMOND_VEL_Y + INTERNAL_HEIGHT, 326 mptr->pixel.x, mptr->pixel.y + CELL_HEIGHT - 327 DIAMOND_VEL_Y - INTERNAL_HEIGHT, &sprites[SPRITE_CENTER_BASE]); 328 } 329 else 330 { 331 nptr = cptr + CELL_STRIDE; 332 nptr[0].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 333 connect_hole(nptr); 334 munch_hole(nptr, mptr->pixel.x, mptr->pixel.y); 335 if(nptr->sprite) 336 back_sprite(nptr->sprite, 0, mptr->pixel.x, mptr->pixel.y); 337 mptr->offset.y = 0; 338 mptr->cell.y += 1; 339 global.broken = 1; 340 } 341 assert(update.set); 342 bounding_box(mptr->pixel.x, mptr->pixel.y, CELL_WIDTH, CELL_HEIGHT); 343 bounding_box(mptr->old_pixel.x, mptr->old_pixel.y, 344 CELL_WIDTH, CELL_HEIGHT); 345 add_background(update.tl.x, update.tl.y, 346 (unsigned)(update.br.x - update.tl.x), 347 (unsigned)(update.br.y - update.tl.y)); 348 } 349 return nptr; 350 } 351 /*}}}*/ 352 /*{{{ CELL *move_movable(mptr, cptr)*/ 353 extern CELL *move_movable 354 FUNCARG((mptr, cptr), 355 MONSTER *mptr 356 ARGSEP CELL *cptr 357 ) 358 /* 359 * move a non muncher down a path 360 * we should never leave known territory 361 */ 362 { 363 unsigned delta; 364 365 switch(mptr->dir) 366 { 367 /*{{{ case 0: (up)*/ 368 case 0: 369 if(!mptr->fast) 370 delta = VEL_Y; 371 else if(mptr->offset.y > 372 (CELL_HEIGHT + GAP_HEIGHT) - (FAST_STEPS * VEL_Y_FAST)) 373 delta = VEL_Y_FAST; 374 else if(mptr->offset.y > (VEL_Y_FAST * FAST_STEPS)) 375 delta = VEL_Y; 376 else if(mptr->offset.y > -(VEL_Y_FAST * FAST_STEPS)) 377 delta = VEL_Y_FAST; 378 else if(mptr->offset.y > 379 (VEL_Y_FAST * FAST_STEPS) - (CELL_HEIGHT + GAP_HEIGHT)) 380 delta = VEL_Y; 381 else 382 delta = VEL_Y_FAST; 383 mptr->pixel.y -= delta; 384 mptr->offset.y -= delta; 385 if(mptr->offset.y == -(CELL_HEIGHT + GAP_HEIGHT) && mptr->cell.y) 386 { 387 mptr->offset.y = 0; 388 mptr->cell.y -= 1; 389 cptr -= CELL_STRIDE; 390 if(!cptr->visit) 391 { 392 if(mptr->offset.x < 0) 393 { 394 mptr->offset.x += CELL_WIDTH + GAP_WIDTH; 395 mptr->cell.x -= 1; 396 cptr -= 1; 397 } 398 else if(mptr->offset.x > 0) 399 { 400 mptr->offset.x -= CELL_WIDTH + GAP_WIDTH; 401 mptr->cell.x += 1; 402 cptr += 1; 403 } 404 else 405 { 406 mptr->offset.y = -(CELL_HEIGHT + GAP_HEIGHT); 407 mptr->cell.y += 1; 408 cptr += CELL_STRIDE; 409 } 410 } 411 } 412 assert(cptr->visit && mptr->cell.y >= 0); 413 assert(mptr->offset.y >= -(CELL_HEIGHT + GAP_HEIGHT)); 414 break; 415 /*}}}*/ 416 /*{{{ case 1: (down)*/ 417 case 1: 418 if(!mptr->fast) 419 delta = VEL_Y; 420 else if(mptr->offset.y < 421 (FAST_STEPS * VEL_Y_FAST) - (CELL_HEIGHT + GAP_HEIGHT)) 422 delta = VEL_Y_FAST; 423 else if(mptr->offset.y < -(VEL_Y_FAST * FAST_STEPS)) 424 delta = VEL_Y; 425 else if(mptr->offset.y < (VEL_Y_FAST * FAST_STEPS)) 426 delta = VEL_Y_FAST; 427 else if(mptr->offset.y < 428 (CELL_HEIGHT + GAP_HEIGHT) - (VEL_Y_FAST * FAST_STEPS)) 429 delta = VEL_Y; 430 else 431 delta = VEL_Y_FAST; 432 mptr->pixel.y += delta; 433 mptr->offset.y += delta; 434 if(mptr->offset.y == CELL_HEIGHT + GAP_HEIGHT) 435 { 436 mptr->offset.y = 0; 437 mptr->cell.y += 1; 438 cptr += CELL_STRIDE; 439 if(!cptr->visit) 440 { 441 if(mptr->offset.x < 0) 442 { 443 mptr->offset.x += CELL_WIDTH + GAP_WIDTH; 444 mptr->cell.x -= 1; 445 cptr -= 1; 446 } 447 else if(mptr->offset.x > 0) 448 { 449 mptr->offset.x -= CELL_WIDTH + GAP_WIDTH; 450 mptr->cell.x += 1; 451 cptr += 1; 452 } 453 else 454 { 455 mptr->offset.y = CELL_HEIGHT + GAP_HEIGHT; 456 mptr->cell.y -= 1; 457 cptr -= CELL_STRIDE; 458 } 459 } 460 } 461 assert(cptr->visit && mptr->cell.y < CELLS_DOWN); 462 assert(mptr->offset.y <= CELL_HEIGHT + GAP_HEIGHT); 463 break; 464 /*}}}*/ 465 /*{{{ case 2: (left)*/ 466 case 2: 467 if(!mptr->fast) 468 delta = VEL_X; 469 else if(mptr->offset.x > 470 (CELL_WIDTH + GAP_WIDTH) - (VEL_X_FAST * FAST_STEPS)) 471 delta = VEL_X_FAST; 472 else if(mptr->offset.x > (VEL_X_FAST * FAST_STEPS)) 473 delta = VEL_X; 474 else if(mptr->offset.x > -(VEL_X_FAST * FAST_STEPS)) 475 delta = VEL_X_FAST; 476 else if(mptr->offset.x > 477 (FAST_STEPS * VEL_X_FAST) - (CELL_WIDTH + GAP_WIDTH)) 478 delta = VEL_X; 479 else 480 delta = VEL_X_FAST; 481 mptr->pixel.x -= delta; 482 mptr->offset.x -= delta; 483 if(mptr->offset.x == -(CELL_WIDTH + GAP_WIDTH) && cptr[-1].visit) 484 { 485 mptr->offset.x = 0; 486 mptr->cell.x -= 1; 487 cptr -= 1; 488 } 489 assert(cptr->visit && !mptr->offset.y && mptr->cell.x >= 0); 490 assert(mptr->offset.x >= -(CELL_WIDTH + GAP_WIDTH)); 491 break; 492 /*}}}*/ 493 /*{{{ case 3: (right)*/ 494 case 3: 495 if(!mptr->fast) 496 delta = VEL_X; 497 else if(mptr->offset.x < 498 (FAST_STEPS * VEL_X_FAST) - (CELL_WIDTH + GAP_WIDTH)) 499 delta = VEL_X_FAST; 500 else if(mptr->offset.x < -(VEL_X_FAST * FAST_STEPS)) 501 delta = VEL_X; 502 else if(mptr->offset.x < (VEL_X_FAST * FAST_STEPS)) 503 delta = VEL_X_FAST; 504 else if(mptr->offset.x < 505 (CELL_WIDTH + GAP_WIDTH) - (VEL_X_FAST * FAST_STEPS)) 506 delta = VEL_X; 507 else 508 delta = VEL_X_FAST; 509 mptr->pixel.x += delta; 510 mptr->offset.x += delta; 511 if(mptr->offset.x == CELL_WIDTH + GAP_WIDTH && cptr[1].visit) 512 { 513 mptr->offset.x = 0; 514 mptr->cell.x += 1; 515 cptr += 1; 516 } 517 assert(cptr->visit && !mptr->offset.y && mptr->cell.x < CELLS_ACROSS); 518 assert(mptr->offset.x <= CELL_WIDTH + GAP_WIDTH); 519 break; 520 /*}}}*/ 521 } 522 return cptr; 523 } 524 /*}}}*/ 525 /*{{{ CELL *move_muncher(mptr)*/ 526 extern CELL *move_muncher 527 FUNCARG((mptr), 528 MONSTER *mptr /* the object to move */ 529 ) 530 /* 531 * moves and munches the board for an object which can munch 532 * apple checking is performed here too 533 * (ie the man, or a munch monster) 534 * the board array is updated as required 535 * returns a pointer to the new cell, if we have arrived elsewhere 536 * or NULL if we stayed on the same cell 537 */ 538 { 539 unsigned broke; 540 CELL *nptr; 541 CELL *cherry; 542 CELL *cptr; 543 COORD pixel; 544 COORD cell; 545 SPRITE *sptr; 546 int knocked; 547 548 assert(!mptr->stop && !mptr->pause); 549 broke = 0; 550 nptr = NULL; 551 cherry = NULL; 552 update.set = 0; 553 cell.x = mptr->cell.x; 554 cell.y = mptr->cell.y; 555 cptr = BOARDCELL(cell.x, cell.y); 556 pixel.x = PIXELX(cell.x, 0); 557 pixel.y = PIXELY(cell.y, 0); 558 knocked = 0; 559 if(!apple_stop(mptr, cptr)) 560 { 561 switch(mptr->dir) 562 { 563 /*{{{ case 0: (up)*/ 564 case 0: 565 /* 566 * if the depth upwards is less than the future depth, 567 * then we have to do some munching 568 */ 569 mptr->offset.y -= VEL_Y; 570 mptr->pixel.y = pixel.y + mptr->offset.y; 571 if(cptr[0].depths[0] > mptr->offset.y) 572 /*{{{ munch*/ 573 { 574 cptr[0].depths[0] = mptr->offset.y; 575 sptr = &sprites[SPRITE_CENTER_BASE]; 576 munch_back(0, 0, CELL_WIDTH, VEL_Y + INTERNAL_HEIGHT, 577 pixel.x, pixel.y + cptr->depths[0], sptr); 578 if(cptr->sprite && mptr->offset.y + VEL_Y + INTERNAL_HEIGHT > 0) 579 back_sprite(cptr->sprite, 0, pixel.x, pixel.y); 580 if(mptr->offset.y < -GAP_HEIGHT) 581 cherry = cptr - CELL_STRIDE; 582 if(INRANGE(mptr->offset.y, 583 1 - (GAP_HEIGHT + VEL_Y), 1 - GAP_HEIGHT) && 584 cptr[-CELL_STRIDE].visit) 585 { 586 cptr[0].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 587 cptr[-CELL_STRIDE].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 588 munch_edge_above(cptr, pixel.x, pixel.y, 1); 589 broke = 1; 590 } 591 if(INRANGE(mptr->offset.y, 592 1 - (INTERNAL_HEIGHT + EXTERNAL_HEIGHT) - VEL_Y, 593 1 - (INTERNAL_HEIGHT + EXTERNAL_HEIGHT))) 594 { 595 sptr = &sprites[SPRITE_EDGE_BASE + 1]; 596 /*{{{ round top left corner?*/ 597 if(cptr[0].depths[2] <= -(INTERNAL_WIDTH + EXTERNAL_WIDTH)) 598 munch_back((EDGE_WIDTH >> 1) - (CELL_WIDTH >> 1) - 599 EXTERNAL_WIDTH, 3 * GAP_HEIGHT - EXTERNAL_HEIGHT, 600 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 601 pixel.x - EXTERNAL_WIDTH, pixel.y - EXTERNAL_HEIGHT, 602 sptr); 603 /*}}}*/ 604 /*{{{ round top right corner?*/ 605 if(cptr[0].depths[3] >= (INTERNAL_WIDTH + EXTERNAL_WIDTH)) 606 munch_back((EDGE_WIDTH >> 1) + (CELL_WIDTH >> 1), 607 3 * GAP_HEIGHT - EXTERNAL_HEIGHT, 608 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 609 pixel.x + CELL_WIDTH, 610 pixel.y - EXTERNAL_HEIGHT, sptr); 611 /*}}}*/ 612 } 613 /*{{{ knocked through?*/ 614 /* 615 * have we bumped into any of the following ? 616 * path from 2 above me 617 * path from above left 618 * path from above right 619 */ 620 if(!cptr[-CELL_STRIDE].visit && 621 ((cptr[-CELL_STRIDE * 2].depths[1] - cptr[0].depths[0] >= 622 CELL_HEIGHT + GAP_HEIGHT * 2) || 623 (cptr[-CELL_STRIDE - 1].depths[3] >= GAP_WIDTH && 624 cptr[-CELL_STRIDE - 1].depths[3] - cptr[0].depths[0] >= 625 KNOCK_THROUGH) || 626 (cptr[-CELL_STRIDE + 1].depths[2] <= -GAP_WIDTH && 627 cptr[-CELL_STRIDE + 1].depths[2] + cptr[0].depths[0] <= 628 -KNOCK_THROUGH))) 629 { 630 knocked = -CELL_STRIDE; 631 cell.y -= 1; 632 } 633 /*}}}*/ 634 if(cptr->depths[0] == -(CELL_HEIGHT + GAP_HEIGHT)) 635 { 636 cptr[-CELL_STRIDE].visit = 1; 637 cptr[-CELL_STRIDE].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 638 broke = 1; 639 } 640 } 641 /*}}}*/ 642 pixel.y -= CELL_HEIGHT + GAP_HEIGHT; 643 if(mptr->offset.y == -(CELL_HEIGHT + GAP_HEIGHT)) 644 { 645 mptr->offset.y = 0; 646 mptr->cell.y--; 647 nptr = cptr - CELL_STRIDE; 648 } 649 break; 650 /*}}}*/ 651 /*{{{ case 1: (down)*/ 652 case 1: 653 { 654 mptr->offset.y += VEL_Y; 655 mptr->pixel.y = pixel.y + mptr->offset.y; 656 if(cptr->depths[1] < mptr->offset.y) 657 /*{{{ munch*/ 658 { 659 cptr->depths[1] = mptr->offset.y; 660 sptr = &sprites[SPRITE_CENTER_BASE]; 661 munch_back(0, CELL_HEIGHT - VEL_Y - INTERNAL_HEIGHT, 662 CELL_WIDTH, VEL_Y + INTERNAL_HEIGHT, 663 pixel.x, pixel.y + cptr[0].depths[1] + 664 CELL_HEIGHT - VEL_Y - INTERNAL_HEIGHT, sptr); 665 if(cptr->sprite && mptr->offset.y < VEL_Y + INTERNAL_HEIGHT) 666 back_sprite(cptr->sprite, 0, pixel.x, pixel.y); 667 if(mptr->offset.y > GAP_HEIGHT) 668 cherry = cptr + CELL_STRIDE; 669 if(INRANGE(mptr->offset.y, GAP_HEIGHT, GAP_HEIGHT + VEL_Y) && 670 cptr[CELL_STRIDE].visit) 671 { 672 cptr[0].depths[1] = CELL_HEIGHT + GAP_HEIGHT; 673 cptr[CELL_STRIDE].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 674 munch_edge_below(cptr, pixel.x, pixel.y, 0, 1); 675 broke = 1; 676 } 677 if(INRANGE(mptr->offset.y, INTERNAL_HEIGHT + EXTERNAL_HEIGHT, 678 INTERNAL_HEIGHT + EXTERNAL_HEIGHT + VEL_Y)) 679 { 680 sptr = &sprites[SPRITE_EDGE_BASE + 1]; 681 /*{{{ round bottom left corner?*/ 682 if(cptr[0].depths[2] <= -(INTERNAL_WIDTH + EXTERNAL_WIDTH)) 683 munch_back((EDGE_WIDTH >> 1) - (CELL_WIDTH >> 1) - 684 EXTERNAL_WIDTH, GAP_HEIGHT, 685 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 686 pixel.x - EXTERNAL_WIDTH, pixel.y + CELL_HEIGHT, 687 sptr); 688 /*}}}*/ 689 /*{{{ round bottom right corner?*/ 690 if(cptr[0].depths[3] >= (INTERNAL_WIDTH + EXTERNAL_WIDTH)) 691 munch_back((EDGE_WIDTH >> 1) + (CELL_WIDTH >> 1), 692 GAP_HEIGHT, 693 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 694 pixel.x + CELL_WIDTH, pixel.y + CELL_HEIGHT, sptr); 695 /*}}}*/ 696 } 697 /*{{{ knocked through?*/ 698 /* 699 * have we bumped into any of the following ? 700 * path from 2 below me 701 * path from below left 702 * path from below right 703 */ 704 if(!cptr[CELL_STRIDE].visit && 705 ((cptr[0].depths[1] - cptr[CELL_STRIDE * 2].depths[0] >= 706 CELL_HEIGHT + GAP_HEIGHT * 2) || 707 (cptr[CELL_STRIDE - 1].depths[3] >= GAP_WIDTH && 708 cptr[CELL_STRIDE - 1].depths[3] + cptr[0].depths[1] >= 709 KNOCK_THROUGH) || 710 (cptr[CELL_STRIDE + 1].depths[2] <= -GAP_WIDTH && 711 cptr[0].depths[1] - cptr[CELL_STRIDE + 1].depths[2] >= 712 KNOCK_THROUGH))) 713 { 714 knocked = CELL_STRIDE; 715 cell.y += 1; 716 } 717 /*}}}*/ 718 if(cptr->depths[1] == (CELL_HEIGHT + GAP_HEIGHT)) 719 { 720 cptr[CELL_STRIDE].visit = 1; 721 cptr[CELL_STRIDE].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT); 722 broke = 1; 723 } 724 } 725 /*}}}*/ 726 pixel.y += CELL_HEIGHT + GAP_HEIGHT; 727 if(mptr->offset.y == (CELL_HEIGHT + GAP_HEIGHT)) 728 { 729 mptr->offset.y = 0; 730 mptr->cell.y++; 731 nptr = cptr + CELL_STRIDE; 732 } 733 break; 734 } 735 /*}}}*/ 736 /*{{{ case 2: (left)*/ 737 case 2: 738 { 739 mptr->offset.x -= VEL_X; 740 mptr->pixel.x = pixel.x + mptr->offset.x; 741 if(cptr[0].depths[2] > mptr->offset.x) 742 /*{{{ munch*/ 743 { 744 cptr[0].depths[2] = mptr->offset.x; 745 sptr = &sprites[SPRITE_CENTER_BASE]; 746 munch_back(0, 0, VEL_X + INTERNAL_WIDTH, CELL_HEIGHT, 747 pixel.x + cptr[0].depths[2], pixel.y, sptr); 748 if(cptr->sprite && mptr->offset.x + VEL_X + INTERNAL_WIDTH > 0) 749 back_sprite(cptr->sprite, 0, pixel.x, pixel.y); 750 if(mptr->offset.x < -GAP_WIDTH) 751 cherry = cptr - 1; 752 if(INRANGE(mptr->offset.x, 1 - (GAP_WIDTH + VEL_X), 753 1 - GAP_WIDTH) && cptr[-1].visit) 754 { 755 cptr[0].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 756 cptr[-1].depths[3] = CELL_WIDTH + GAP_WIDTH; 757 munch_edge_left(cptr, pixel.x, pixel.y, 1); 758 broke = 1; 759 } 760 if(INRANGE(mptr->offset.x, 761 1 - (INTERNAL_WIDTH + EXTERNAL_WIDTH) - VEL_X, 762 1 - (INTERNAL_WIDTH + EXTERNAL_WIDTH))) 763 { 764 sptr = &sprites[SPRITE_EDGE_BASE + 0]; 765 /*{{{ round left top corner?*/ 766 if(cptr[0].depths[0] <= 767 -(INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 768 munch_back(3 * GAP_WIDTH - EXTERNAL_WIDTH, 769 (EDGE_HEIGHT >> 1) - (CELL_HEIGHT >> 1) - 770 EXTERNAL_HEIGHT, EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 771 pixel.x - EXTERNAL_WIDTH, pixel.y - EXTERNAL_HEIGHT, 772 sptr); 773 /*}}}*/ 774 /*{{{ round left bottom corner?*/ 775 if(cptr[0].depths[1] >= (INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 776 munch_back(3 * GAP_HEIGHT - EXTERNAL_WIDTH, 777 (EDGE_HEIGHT >> 1) + (CELL_HEIGHT >> 1), 778 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 779 pixel.x - EXTERNAL_WIDTH, 780 pixel.y + CELL_HEIGHT, sptr); 781 /*}}}*/ 782 } 783 /*{{{ knocked through?*/ 784 /* 785 * have we bumped into any of the following ? 786 * path from 2 left me 787 * path from left above 788 * path from left below 789 */ 790 if(!cptr[-1].visit && 791 ((cptr[-2].depths[3] - cptr[0].depths[2] >= 792 CELL_WIDTH + GAP_WIDTH * 2) || 793 (cptr[-CELL_STRIDE - 1].depths[1] >= GAP_HEIGHT && 794 cptr[-CELL_STRIDE - 1].depths[1] - cptr[0].depths[2] >= 795 KNOCK_THROUGH) || 796 (cptr[CELL_STRIDE - 1].depths[0] <= -GAP_HEIGHT && 797 cptr[CELL_STRIDE - 1].depths[0] + cptr[0].depths[2] <= 798 -KNOCK_THROUGH))) 799 { 800 knocked = -1; 801 cell.x -= 1; 802 } 803 /*}}}*/ 804 if(cptr->depths[2] == -(CELL_WIDTH + GAP_WIDTH)) 805 { 806 cptr[-1].visit = 1; 807 cptr[-1].depths[3] = CELL_WIDTH + GAP_WIDTH; 808 broke = 1; 809 } 810 } 811 /*}}}*/ 812 pixel.x -= CELL_WIDTH + GAP_WIDTH; 813 if(mptr->offset.x == -(CELL_WIDTH + GAP_WIDTH)) 814 { 815 mptr->offset.x = 0; 816 mptr->cell.x--; 817 nptr = cptr - 1; 818 } 819 break; 820 } 821 /*}}}*/ 822 /*{{{ case 3: (right)*/ 823 case 3: 824 { 825 mptr->offset.x += VEL_X; 826 mptr->pixel.x = pixel.x + mptr->offset.x; 827 if(cptr->depths[3] < mptr->offset.x) 828 /*{{{ munch*/ 829 { 830 cptr->depths[3] = mptr->offset.x; 831 sptr = &sprites[SPRITE_CENTER_BASE]; 832 munch_back(CELL_WIDTH - VEL_X - INTERNAL_WIDTH, 0, 833 VEL_X + INTERNAL_WIDTH, CELL_HEIGHT, 834 pixel.x + cptr->depths[3] + 835 CELL_WIDTH - VEL_X - INTERNAL_WIDTH, pixel.y, sptr); 836 if(cptr->sprite && mptr->offset.x < VEL_X + INTERNAL_WIDTH) 837 back_sprite(cptr->sprite, 0, pixel.x, pixel.y); 838 if(mptr->offset.x > GAP_WIDTH) 839 cherry = cptr + 1; 840 if(INRANGE(mptr->offset.x, GAP_WIDTH, GAP_WIDTH + VEL_X) && 841 cptr[1].visit) 842 { 843 cptr[0].depths[3] = CELL_WIDTH + GAP_WIDTH; 844 cptr[1].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 845 munch_edge_right(cptr, pixel.x, pixel.y, 1); 846 broke = 1; 847 } 848 if(INRANGE(mptr->offset.x, INTERNAL_WIDTH + EXTERNAL_WIDTH, 849 INTERNAL_WIDTH + EXTERNAL_WIDTH + VEL_X)) 850 { 851 sptr = &sprites[SPRITE_EDGE_BASE + 0]; 852 /*{{{ round right top corner?*/ 853 if(cptr[0].depths[0] <= 854 -(INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 855 munch_back(GAP_HEIGHT, (EDGE_HEIGHT >> 1) - 856 (CELL_HEIGHT >> 1) - EXTERNAL_HEIGHT, 857 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 858 pixel.x + CELL_WIDTH, pixel.y - EXTERNAL_HEIGHT, 859 sptr); 860 /*}}}*/ 861 /*{{{ round right bottom corner?*/ 862 if(cptr[0].depths[1] >= (INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 863 munch_back(GAP_WIDTH, 864 (EDGE_HEIGHT >> 1) + (CELL_WIDTH >> 1), 865 EXTERNAL_WIDTH, EXTERNAL_HEIGHT, 866 pixel.x + CELL_WIDTH, pixel.y + CELL_HEIGHT, sptr); 867 /*}}}*/ 868 } 869 /*{{{ knocked through?*/ 870 /* 871 * have we bumped into any of the following ? 872 * path from 2 right me 873 * path from right above 874 * path from right below 875 */ 876 if(!cptr[1].visit && ((cptr[0].depths[3] - cptr[2].depths[2] >= 877 CELL_WIDTH + GAP_WIDTH * 2) || 878 (cptr[-CELL_STRIDE + 1].depths[1] >= GAP_HEIGHT && 879 cptr[-CELL_STRIDE + 1].depths[1] + cptr[0].depths[3] >= 880 KNOCK_THROUGH) || 881 (cptr[CELL_STRIDE + 1].depths[0] <= -GAP_HEIGHT && 882 cptr[0].depths[3] - cptr[CELL_STRIDE + 1].depths[0] >= 883 KNOCK_THROUGH))) 884 { 885 knocked = 1; 886 cell.x += 1; 887 } 888 /*}}}*/ 889 if(cptr->depths[3] == (CELL_WIDTH + GAP_WIDTH)) 890 { 891 cptr[1].visit = 1; 892 cptr[1].depths[2] = -(CELL_WIDTH + GAP_WIDTH); 893 broke = 1; 894 } 895 } 896 /*}}}*/ 897 pixel.x += CELL_WIDTH + GAP_WIDTH; 898 if(mptr->offset.x == (CELL_WIDTH + GAP_WIDTH)) 899 { 900 mptr->offset.x = 0; 901 mptr->cell.x++; 902 nptr = cptr + 1; 903 } 904 break; 905 } 906 /*}}}*/ 907 } 908 } 909 /*{{{ knocked through?*/ 910 /* 911 * if we knocked through to an adjoining cell 912 * we clear out the specified cell and check all the corners 913 * note, cell has already been altered correctly 914 * we must also check to se if this launches an apple 915 */ 916 if(knocked) 917 { 918 broke = 1; 919 assert(!cherry || cherry == cptr + knocked); 920 cherry = cptr += knocked; 921 connect_hole(cptr); 922 munch_hole(cptr, pixel.x, pixel.y); 923 } 924 /*}}}*/ 925 /*{{{ redraw or blank prize?*/ 926 if(nptr && nptr->sprite) 927 { 928 assert(!cherry || cherry == nptr); 929 if((mptr->type != 4 && nptr->sprite >= SPRITE_PRIZE_BASE) || 930 (nptr->sprite != SPRITE_CHERRY && nptr->sprite < SPRITE_PRIZE_BASE)) 931 back_sprite(nptr->sprite, 0, pixel.x, pixel.y); 932 else 933 munch_back(0, 0, CELL_WIDTH, CELL_HEIGHT, 934 pixel.x, pixel.y, &sprites[SPRITE_CENTER_BASE + 935 (nptr->sprite != SPRITE_CHERRY)]); 936 } 937 else if(cherry && cherry->sprite) 938 back_sprite(cherry->sprite, 0, pixel.x, pixel.y); 939 /*}}}*/ 940 if(update.set) 941 { 942 bounding_box(mptr->pixel.x, mptr->pixel.y, CELL_WIDTH, CELL_HEIGHT); 943 bounding_box(mptr->old_pixel.x, mptr->old_pixel.y, 944 CELL_WIDTH, CELL_HEIGHT); 945 add_background(update.tl.x, update.tl.y, 946 (unsigned)(update.br.x - update.tl.x), 947 (unsigned)(update.br.y - update.tl.y)); 948 mptr->back = 1; 949 } 950 if(broke) 951 global.broken = 1; 952 /* check we haven't wandered off the board */ 953 assert(!nptr || nptr->visit); 954 assert(INRANGE(mptr->cell.y, 0, CELLS_DOWN)); 955 assert(INRANGE(mptr->cell.x, 0, CELLS_ACROSS)); 956 assert(mptr->cell.x || mptr->offset.x >= 0); 957 assert(mptr->cell.y || mptr->offset.y >= 0); 958 assert(mptr->cell.x < CELLS_ACROSS - 1 || mptr->offset.x <= 0); 959 assert(mptr->cell.y < CELLS_DOWN - 1 || mptr->offset.y <= 0); 960 assert(!mptr->offset.x || !mptr->offset.y); 961 return nptr; 962 } 963 /*}}}*/ 964 /*{{{ void munch_back(sx, sy, width, height, dx, dy, sprite)*/ 965 static VOIDFUNC munch_back 966 FUNCARG((sx, sy, width, height, dx, dy, sprite), 967 int sx 968 ARGSEP int sy 969 ARGSEP unsigned width 970 ARGSEP unsigned height 971 ARGSEP int dx 972 ARGSEP int dy 973 ARGSEP SPRITE CONST *sprite 974 ) 975 /* 976 * munches the background image with the specified sprite 977 */ 978 { 979 if(display.background != COLOUR_ONE) 980 XCopyArea(display.display, sprite->mask, display.back, GCN(GC_MASK), 981 sx, sy, width, height, dx, dy); 982 if(display.background != COLOUR_ZERO) 983 XCopyArea(display.display, sprite->image, display.back, GCN(GC_OR), 984 sx, sy, width, height, dx, dy); 985 bounding_box(dx, dy, width, height); 986 return; 987 } 988 /*}}}*/ 989 /*{{{ void munch_hole(cptr, x, y)*/ 990 extern VOIDFUNC munch_hole 991 FUNCARG((cptr, x, y), 992 CELL *cptr 993 ARGSEP int x 994 ARGSEP int y 995 ) 996 /* 997 * cut out the background for a whole cell, and 998 * deal with connections to the adjoining cells 999 * don't forget to replot the cherry 1000 */ 1001 { 1002 /*{{{ cut out the center*/ 1003 { 1004 SPRITE *sptr; 1005 1006 sptr = &sprites[SPRITE_CENTER_BASE]; 1007 munch_back(0, 0, 1008 CELL_WIDTH >> 1, CELL_HEIGHT >> 1, 1009 x, y, 1010 &sptr[!!(cptr[0].depths[0] || cptr[0].depths[2])]); 1011 munch_back(CELL_WIDTH >> 1, 0, 1012 CELL_WIDTH >> 1, CELL_HEIGHT >> 1, 1013 x + (CELL_WIDTH >> 1), y, 1014 &sptr[!!(cptr[0].depths[0] || cptr[0].depths[3])]); 1015 munch_back(CELL_WIDTH >> 1, CELL_HEIGHT >> 1, 1016 CELL_WIDTH >> 1, CELL_HEIGHT >> 1, 1017 x + (CELL_WIDTH >> 1), y + (CELL_HEIGHT >> 1), 1018 &sptr[!!(cptr[0].depths[1] || cptr[0].depths[3])]); 1019 munch_back(0, CELL_HEIGHT >> 1, 1020 CELL_WIDTH >> 1, CELL_HEIGHT >> 1, 1021 x, y + (CELL_HEIGHT >> 1), 1022 &sptr[!!(cptr[0].depths[1] || cptr[0].depths[2])]); 1023 } 1024 /*}}}*/ 1025 if(cptr[0].depths[0] <= -GAP_HEIGHT && cptr[-CELL_STRIDE].visit) 1026 munch_edge_above(cptr, x, y, 0); 1027 if(cptr[0].depths[1] >= GAP_HEIGHT && cptr[CELL_STRIDE].visit) 1028 munch_edge_below(cptr, x, y, 0, 0); 1029 if(cptr[0].depths[2] <= -GAP_WIDTH && cptr[-1].visit) 1030 munch_edge_left(cptr, x, y, 0); 1031 if(cptr[0].depths[3] >= GAP_WIDTH && cptr[1].visit) 1032 munch_edge_right(cptr, x, y, 0); 1033 return; 1034 } 1035 /*}}}*/ 1036 /*{{{ void munch_edge_above(cptr, x, y, flag)*/ 1037 static VOIDFUNC munch_edge_above 1038 FUNCARG((cptr, x, y, flag), 1039 CELL *cptr 1040 ARGSEP int x 1041 ARGSEP int y 1042 ARGSEP unsigned flag 1043 ) 1044 /* 1045 * munches an edge above the cell, replots the cherry above if needed 1046 */ 1047 { 1048 unsigned check; 1049 /* remember kiddies, never leave signed cheques lying about */ 1050 unsigned type; 1051 SPRITE *sptr; 1052 1053 sptr = &sprites[SPRITE_EDGE_BASE + 1]; 1054 check = 0; 1055 type = 0; 1056 if(cptr[0].depths[2] <= -(INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1057 type = 2 * GAP_HEIGHT; 1058 if(cptr[-CELL_STRIDE].depths[2] <= -(INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1059 type += GAP_HEIGHT; 1060 if(type == 3 * GAP_HEIGHT && (cptr[-CELL_STRIDE - 1].depths[1] - 1061 cptr[-1].depths[0] >= GAP_HEIGHT)) 1062 type = 4 * GAP_HEIGHT; 1063 munch_back(0, (int)type, EDGE_WIDTH >> 1, GAP_HEIGHT, 1064 x + (CELL_WIDTH >> 1) - (EDGE_WIDTH >> 1), y - GAP_HEIGHT, sptr); 1065 if(flag && !cptr[-CELL_STRIDE].depths[2]) 1066 { 1067 check = 1; 1068 munch_back(0, 0, EDGE_WIDTH >> 1, GAP_HEIGHT, 1069 x + (CELL_WIDTH >> 1) - (EDGE_WIDTH >> 1), 1070 y - GAP_HEIGHT * 2, sptr); 1071 } 1072 type = 0; 1073 if(cptr[0].depths[3] >= (INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1074 type = 2 * GAP_HEIGHT; 1075 if(cptr[-CELL_STRIDE].depths[3] >= (INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1076 type += GAP_HEIGHT; 1077 if(type == 3 * GAP_HEIGHT && (cptr[-CELL_STRIDE + 1].depths[1] - 1078 cptr[1].depths[0] >= GAP_HEIGHT)) 1079 type = 4 * GAP_HEIGHT; 1080 munch_back(EDGE_WIDTH >> 1, (int)type, EDGE_WIDTH >> 1, GAP_HEIGHT, 1081 x + (CELL_WIDTH >> 1), y - GAP_HEIGHT, sptr); 1082 if(flag && !cptr[-CELL_STRIDE].depths[3]) 1083 { 1084 check = 1; 1085 munch_back(EDGE_WIDTH >> 1, 0, EDGE_WIDTH >> 1, GAP_HEIGHT, 1086 x + (CELL_WIDTH >> 1), y - GAP_HEIGHT * 2, sptr); 1087 } 1088 if(check && cptr[-CELL_STRIDE].sprite) 1089 back_sprite(cptr[-CELL_STRIDE].sprite, 0, 1090 x, y - CELL_HEIGHT - GAP_HEIGHT); 1091 return; 1092 } 1093 /*}}}*/ 1094 /*{{{ void munch_edge_below(cptr, x, y, offset, flag)*/ 1095 static VOIDFUNC munch_edge_below 1096 FUNCARG((cptr, x, y, offset, flag), 1097 CELL *cptr 1098 ARGSEP int x 1099 ARGSEP int y 1100 ARGSEP int offset 1101 ARGSEP unsigned flag 1102 ) 1103 /* 1104 * munches an edge below the cell, replots the cherry above if needed 1105 * the edge can be offset, in the case of non-aligned apples 1106 */ 1107 { 1108 unsigned check; 1109 unsigned type; 1110 SPRITE *sptr; 1111 1112 sptr = &sprites[SPRITE_EDGE_BASE + 1]; 1113 check = 0; 1114 type = 0; 1115 if(cptr[0].depths[2] - offset <= -(INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1116 type = GAP_HEIGHT; 1117 if(cptr[CELL_STRIDE].depths[2] - offset <= 1118 -(INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1119 type += 2 * GAP_HEIGHT; 1120 if(!offset && type == 3 * GAP_HEIGHT && (cptr[-1].depths[1] - 1121 cptr[CELL_STRIDE - 1].depths[0] >= GAP_HEIGHT)) 1122 type = 4 * GAP_HEIGHT; 1123 munch_back(0, (int)type, EDGE_WIDTH >> 1, GAP_HEIGHT, 1124 x + (CELL_WIDTH >> 1) - (EDGE_WIDTH >> 1), y + CELL_HEIGHT, sptr); 1125 if(flag && !cptr[CELL_STRIDE].depths[2]) 1126 { 1127 check = 1; 1128 munch_back(0, 0, EDGE_WIDTH >> 1, GAP_HEIGHT, 1129 x + (CELL_WIDTH >> 1) - (EDGE_WIDTH >> 1), 1130 y + CELL_HEIGHT + GAP_HEIGHT, sptr); 1131 } 1132 type = 0; 1133 if(cptr[0].depths[3] - offset >= (INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1134 type = GAP_HEIGHT; 1135 if(cptr[CELL_STRIDE].depths[3] - offset >= 1136 (INTERNAL_WIDTH + EXTERNAL_WIDTH)) 1137 type += 2 * GAP_HEIGHT; 1138 if(!offset && type == 3 * GAP_HEIGHT && 1139 (cptr[1].depths[1] - 1140 cptr[CELL_STRIDE + 1].depths[0] >= GAP_HEIGHT)) 1141 type = 4 * GAP_HEIGHT; 1142 munch_back(EDGE_WIDTH >> 1, (int)type, EDGE_WIDTH >> 1, GAP_HEIGHT, 1143 x + (CELL_WIDTH >> 1), y + CELL_HEIGHT, sptr); 1144 if(flag && !cptr[CELL_STRIDE].depths[3]) 1145 { 1146 check = 1; 1147 munch_back(EDGE_WIDTH >> 1, 0, EDGE_WIDTH >> 1, GAP_HEIGHT, 1148 x + (CELL_WIDTH >> 1), y + CELL_HEIGHT + GAP_HEIGHT, sptr); 1149 } 1150 if(check && cptr[CELL_STRIDE].sprite) 1151 back_sprite(cptr[CELL_STRIDE].sprite, 0, 1152 x, y + CELL_HEIGHT + GAP_HEIGHT); 1153 return; 1154 } 1155 /*}}}*/ 1156 /*{{{ void munch_edge_left(cptr, x, y, flag)*/ 1157 static VOIDFUNC munch_edge_left 1158 FUNCARG((cptr, x, y, flag), 1159 CELL *cptr 1160 ARGSEP int x 1161 ARGSEP int y 1162 ARGSEP unsigned flag 1163 ) 1164 /* 1165 * munches an edge left of the cell, replots the cherry above if needed 1166 */ 1167 { 1168 unsigned check; 1169 unsigned type; 1170 SPRITE *sptr; 1171 1172 sptr = &sprites[SPRITE_EDGE_BASE + 0]; 1173 check = 0; 1174 type = 0; 1175 if(cptr[0].depths[0] <= -(INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1176 type = 2 * GAP_WIDTH; 1177 if(cptr[-1].depths[0] <= -(INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1178 type += GAP_WIDTH; 1179 if(type == 3 * GAP_WIDTH && (cptr[-CELL_STRIDE - 1].depths[3] - 1180 cptr[-CELL_STRIDE].depths[2] >= GAP_WIDTH)) 1181 type = 4 * GAP_WIDTH; 1182 munch_back((int)type, 0, GAP_HEIGHT, EDGE_HEIGHT >> 1, 1183 x - GAP_WIDTH, y + (CELL_HEIGHT >> 1) - (EDGE_HEIGHT >> 1), sptr); 1184 if(flag && !cptr[-1].depths[0]) 1185 { 1186 check = 1; 1187 munch_back(0, 0, GAP_WIDTH, EDGE_HEIGHT >> 1, x - GAP_WIDTH * 2, 1188 y + (CELL_HEIGHT >> 1) - (EDGE_HEIGHT >> 1), sptr); 1189 } 1190 type = 0; 1191 if(cptr[0].depths[1] >= (INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1192 type = 2 * GAP_WIDTH; 1193 if(cptr[-1].depths[1] >= (INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1194 type += GAP_WIDTH; 1195 if(type == 3 * GAP_WIDTH && (cptr[CELL_STRIDE - 1].depths[3] - 1196 cptr[CELL_STRIDE].depths[2] >= GAP_WIDTH)) 1197 type = 4 * GAP_WIDTH; 1198 munch_back((int)type, EDGE_HEIGHT >> 1, GAP_WIDTH, EDGE_HEIGHT >> 1, 1199 x - GAP_WIDTH, y + (CELL_HEIGHT >> 1), sptr); 1200 if(flag && !cptr[-1].depths[1]) 1201 { 1202 check = 1; 1203 munch_back(0, EDGE_HEIGHT >> 1, GAP_WIDTH, EDGE_HEIGHT >> 1, 1204 x - GAP_WIDTH * 2, y + (CELL_HEIGHT >> 1), sptr); 1205 } 1206 if(check && cptr[-1].sprite) 1207 back_sprite(cptr[-1].sprite, 0, x - CELL_WIDTH - GAP_WIDTH, y); 1208 return; 1209 } 1210 /*}}}*/ 1211 /*{{{ void munch_edge_right(cptr, x, y, flag)*/ 1212 static VOIDFUNC munch_edge_right 1213 FUNCARG((cptr, x, y, flag), 1214 CELL *cptr 1215 ARGSEP int x 1216 ARGSEP int y 1217 ARGSEP unsigned flag 1218 ) 1219 /* 1220 * munches an edge right of the cell, replots the cherry above if needed 1221 */ 1222 { 1223 unsigned check; 1224 unsigned type; 1225 SPRITE *sptr; 1226 1227 sptr = &sprites[SPRITE_EDGE_BASE + 0]; 1228 check = 0; 1229 type = 0; 1230 if(cptr[0].depths[0] <= -(INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1231 type = GAP_WIDTH; 1232 if(cptr[1].depths[0] <= -(INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1233 type += 2 * GAP_WIDTH; 1234 if(type == 3 * GAP_WIDTH && 1235 (cptr[-CELL_STRIDE].depths[3] - 1236 cptr[-CELL_STRIDE + 1].depths[2] >= GAP_WIDTH)) 1237 type = 4 * GAP_WIDTH; 1238 munch_back((int)type, 0, GAP_WIDTH, EDGE_HEIGHT >> 1, 1239 x + CELL_WIDTH, y + (CELL_HEIGHT >> 1) - (EDGE_HEIGHT >> 1), sptr); 1240 if(flag && !cptr[1].depths[0]) 1241 { 1242 check = 1; 1243 munch_back(0, 0, GAP_WIDTH, EDGE_HEIGHT >> 1, 1244 x + CELL_WIDTH + GAP_WIDTH, 1245 y + (CELL_HEIGHT >> 1) - (EDGE_HEIGHT >> 1), sptr); 1246 } 1247 type = 0; 1248 if(cptr[0].depths[1] >= (INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1249 type = GAP_WIDTH; 1250 if(cptr[1].depths[1] >= (INTERNAL_HEIGHT + EXTERNAL_HEIGHT)) 1251 type += 2 * GAP_WIDTH; 1252 if(type == 3 * GAP_WIDTH && 1253 (cptr[CELL_STRIDE].depths[3] - 1254 cptr[CELL_STRIDE + 1].depths[2] >= GAP_WIDTH)) 1255 type = 4 * GAP_WIDTH; 1256 munch_back((int)type, EDGE_HEIGHT >> 1, GAP_WIDTH, EDGE_HEIGHT >> 1, 1257 x + CELL_WIDTH, y + (CELL_HEIGHT >> 1), sptr); 1258 if(flag && !cptr[1].depths[1]) 1259 { 1260 check = 1; 1261 munch_back(0, EDGE_HEIGHT >> 1, GAP_WIDTH, EDGE_HEIGHT >> 1, 1262 x + CELL_WIDTH + GAP_WIDTH, y + (CELL_HEIGHT >> 1), sptr); 1263 } 1264 if(check && cptr[1].sprite) 1265 back_sprite(cptr[1].sprite, 0, x + CELL_WIDTH + GAP_WIDTH, y); 1266 return; 1267 } 1268 /*}}}*/ 1269 /*{{{ void new_face(mptr)*/ 1270 extern VOIDFUNC new_face 1271 FUNCARG((mptr), 1272 MONSTER *mptr 1273 ) 1274 /* 1275 * calculates the required face for the direction, 1276 * given the old face 1277 */ 1278 { 1279 int dir; 1280 int face; 1281 1282 if(mptr->push) 1283 dir = mptr->dir ^ 1; 1284 else 1285 dir = mptr->dir; 1286 face = mptr->face < 6 ? mptr->face : 2 + (mptr->face & 1); 1287 if(mptr->squished) 1288 mptr->face = 16 + (face > 2); 1289 else if(dir & 2) 1290 mptr->face = dir; 1291 else if(face == 2) 1292 mptr->face = dir; 1293 else if(face == 3) 1294 mptr->face = dir + 4; 1295 else if((dir ^ face) & 1) 1296 mptr->face ^= 5; 1297 if(mptr->face & 2 && mptr->pushing) 1298 mptr->face += 4; 1299 return; 1300 } 1301 /*}}}*/ 1302 /*{{{ unsigned run_home(mptr, cptr)*/ 1303 extern unsigned run_home 1304 FUNCARG((mptr, cptr), 1305 MONSTER *mptr 1306 ARGSEP CELL *cptr 1307 ) 1308 /* 1309 * sets the direction bit to run home 1310 */ 1311 { 1312 unsigned preferred; 1313 int offset; 1314 1315 if((offset = mptr->offset.y) != 0) 1316 /*{{{ up down only*/ 1317 { 1318 if(offset < 0 ? cptr[0].xtra < 1319 cptr[-CELL_STRIDE].xtra : 1320 cptr[0].xtra >= cptr[CELL_STRIDE].xtra) 1321 preferred = 0x2; 1322 else 1323 preferred = 0x1; 1324 } 1325 /*}}}*/ 1326 else if(cptr->xtra == 1) 1327 preferred = mptr->pixel.x > PIXELX(4, 1328 extra.select * XTRA_SPACING) ? 0x4 : 0x8; 1329 else if((offset = mptr->offset.x) != 0) 1330 /*{{{ left right only*/ 1331 { 1332 if(offset < 0 ? cptr[0].xtra < cptr[-1].xtra : 1333 cptr[0].xtra >= cptr[1].xtra) 1334 preferred = 0x8; 1335 else 1336 preferred = 0x4; 1337 if(offset == cptr->holes[0] || 1338 offset == cptr->holes[1]) 1339 { 1340 if(cptr[0].xtra > cptr[-CELL_STRIDE].xtra) 1341 preferred |= 0x1; 1342 } 1343 if(offset == cptr->holes[2] || 1344 offset == cptr->holes[3]) 1345 { 1346 if(cptr[0].xtra > cptr[CELL_STRIDE].xtra) 1347 preferred |= 0x2; 1348 } 1349 } 1350 /*}}}*/ 1351 else 1352 /*{{{ at intersection*/ 1353 { 1354 int distance; 1355 1356 distance = cptr->xtra; 1357 preferred = 0; 1358 if(distance > cptr[-CELL_STRIDE].xtra) 1359 preferred |= 0x1; 1360 if(distance > cptr[CELL_STRIDE].xtra) 1361 preferred |= 0x2; 1362 if(distance > cptr[-1].xtra) 1363 preferred |= 0x4; 1364 if(distance > cptr[1].xtra) 1365 preferred |= 0x8; 1366 } 1367 /*}}}*/ 1368 return preferred; 1369 } 1370 /*}}}*/ 1371 /*{{{ unsigned valid_directions(mptr, cptr)*/ 1372 extern unsigned valid_directions 1373 FUNCARG((mptr, cptr), 1374 MONSTER *mptr 1375 ARGSEP CELL *cptr 1376 ) 1377 /* 1378 * sets the valid and nearer direction bits 1379 * these are nr, nl, nd, nu, r, l, d, u 1380 */ 1381 { 1382 unsigned answer; 1383 int offset; 1384 1385 answer = 0; 1386 assert(cptr->visit); 1387 if((offset = mptr->offset.y) != 0) 1388 /*{{{ up down only*/ 1389 { 1390 if(!mptr->cell.y && offset < 0) 1391 answer |= 2; 1392 else if(mptr->offset.x) 1393 answer |= 0x3; 1394 else 1395 { 1396 if(offset > cptr->depths[0]) 1397 answer |= 0x1; 1398 if(offset < cptr->depths[1]) 1399 answer |= 0x2; 1400 } 1401 if(cptr == monster.player) 1402 answer |= monster.list[0].offset.y > offset ? 0x20 : 0x10; 1403 else if(offset < 0 ? cptr[0].distance < cptr[-CELL_STRIDE].distance : 1404 cptr[0].distance >= cptr[CELL_STRIDE].distance) 1405 answer |= 0x20; 1406 else 1407 answer |= 0x10; 1408 } 1409 /*}}}*/ 1410 else if((offset = mptr->offset.x) != 0) 1411 /*{{{ left right only*/ 1412 { 1413 if(offset > cptr->depths[2]) 1414 answer |= 0x4; 1415 if(offset < cptr->depths[3]) 1416 answer |= 0x8; 1417 if(cptr == monster.player) 1418 answer |= monster.list[0].offset.x > offset ? 0x80 : 0x40; 1419 else if(offset < 0 ? cptr[0].distance < cptr[-1].distance : 1420 cptr[0].distance >= cptr[1].distance) 1421 answer |= 0x80; 1422 else 1423 answer |= 0x40; 1424 if(offset == cptr->holes[0] || offset == cptr->holes[1]) 1425 { 1426 answer |= 0x1; 1427 if(cptr[0].distance > cptr[-CELL_STRIDE].distance) 1428 answer |= 0x10; 1429 } 1430 if(offset == cptr->holes[2] || offset == cptr->holes[3]) 1431 { 1432 answer |= 0x2; 1433 if(cptr[0].distance > cptr[CELL_STRIDE].distance) 1434 answer |= 0x20; 1435 } 1436 } 1437 /*}}}*/ 1438 else 1439 /*{{{ at intersection*/ 1440 { 1441 int distance; 1442 1443 if(cptr->depths[0]) 1444 answer |= 0x1; 1445 if(cptr->depths[1]) 1446 answer |= 0x2; 1447 if(cptr->depths[2]) 1448 answer |= 0x4; 1449 if(cptr->depths[3]) 1450 answer |= 0x8; 1451 distance = cptr->distance; 1452 if(cptr == monster.player) 1453 { 1454 if(monster.list[0].offset.x < 0) 1455 answer |= 0x40; 1456 else if(monster.list[0].offset.x > 0) 1457 answer |= 0x80; 1458 else if(monster.list[0].offset.y < 0) 1459 answer |= 0x10; 1460 else if(monster.list[0].offset.y > 0) 1461 answer |= 0x20; 1462 } 1463 else 1464 { 1465 if(distance > cptr[-CELL_STRIDE].distance) 1466 answer |= 0x10; 1467 if(distance > cptr[CELL_STRIDE].distance) 1468 answer |= 0x20; 1469 if(distance > cptr[-1].distance) 1470 answer |= 0x40; 1471 if(distance > cptr[1].distance) 1472 answer |= 0x80; 1473 } 1474 } 1475 /*}}}*/ 1476 answer &= answer << 4 | 0xF; 1477 return answer; 1478 } 1479 /*}}}*/ 1480