1 /* Copyright (C) 1993, 1992 Nathan Sidwell */ 2 /* RCS $Id: monster.c,v 4.6 1993/12/10 11:52:23 nathan Stable $ */ 3 #include "xmris.h" 4 /*{{{ MONSTER *extra_escape()*/ 5 extern MONSTER *extra_escape FUNCARGVOID 6 /* 7 * remove the extra monster from the top, so it 8 * can run around 9 */ 10 { 11 int x; 12 13 extra.escape = 1; 14 x = PIXELX(4, extra.select * XTRA_SPACING); 15 XFillRectangle(display.display, display.back, GCN(GC_CLEAR), 16 x, PIXELY(-1, 0), CELL_WIDTH, CELL_HEIGHT); 17 add_background(x, PIXELY(-1, 0), CELL_WIDTH, CELL_HEIGHT); 18 x -= BORDER_LEFT + GAP_WIDTH; 19 return spawn_monster(1, 2, 1, 1, x / (CELL_WIDTH + GAP_WIDTH), 0, 20 x % (CELL_WIDTH + GAP_WIDTH), -CELL_HEIGHT); 21 } 22 /*}}}*/ 23 /*{{{ void extra_dies()*/ 24 extern VOIDFUNC extra_dies FUNCARGVOID 25 /* 26 * the extra monster has died, 27 * put it back at the top 28 * and maybe alter the state 29 */ 30 { 31 unsigned got; 32 33 if(global.state == 2) 34 { 35 color_set(BACKGROUND_NORMAL); 36 global.state = 3; 37 monster.den = 0; 38 monster.delay = 0; 39 } 40 got = extra.got & (1 << extra.select); 41 extra.got |= 1 << extra.select; 42 extra.escape = 0; 43 extra.count = FRAMES_PER_SECOND - 1; 44 if(!got) 45 create_xtra_monster(extra.select); 46 draw_extra(); 47 return; 48 } 49 /*}}}*/ 50 /*{{{ void move_monsters()*/ 51 extern VOIDFUNC move_monsters FUNCARGVOID 52 /* 53 * move all the monsters 54 */ 55 { 56 MONSTER *mptr; 57 unsigned i; 58 unsigned nearest; 59 unsigned farthest; 60 61 nearest = 255; 62 farthest = 0; 63 for(mptr = &monster.list[1], i = monster.monsters - 1; i--; mptr++) 64 { 65 if(mptr->type == 5 || mptr->squished) 66 /* EMPTY */; 67 else if(mptr->shot || (mptr->type == 3 && global.state == 3)) 68 /*{{{ shot*/ 69 { 70 if(BOARDCELL(mptr->cell.x, mptr->cell.y)->distance == 71 monster.nearest) 72 global.difficulty++; 73 if(mptr->type < 2) 74 monster.normals--; 75 else if(mptr->type < 4) 76 /*{{{ convert to apple*/ 77 { 78 APPLE *aptr; 79 80 if(mptr->type == 2) 81 extra_dies(); 82 else if(mptr->type == 3) 83 monster.drones--; 84 if(mptr->offset.x > (CELL_WIDTH + GAP_WIDTH) / 2) 85 { 86 mptr->offset.x -= CELL_WIDTH + GAP_WIDTH; 87 mptr->cell.x++; 88 } 89 else if(mptr->offset.x < -(CELL_WIDTH + GAP_WIDTH) / 2) 90 { 91 mptr->offset.x += CELL_WIDTH + GAP_WIDTH; 92 mptr->cell.x--; 93 } 94 aptr = spawn_apple(mptr->cell.x, mptr->cell.y, 95 mptr->offset.x, mptr->offset.y); 96 if(mptr->type == 3 && global.state == 3) 97 aptr->ghost = APPLE_GHOST_DELAY; 98 } 99 /*}}}*/ 100 else 101 global.diamond = 2; 102 if(mptr->shot) 103 add_score(mptr->type == 6 ? 104 (unsigned)(8000 / SCORE_ROUND) : (unsigned)(500 / SCORE_ROUND), 105 mptr->pixel.x + CELL_WIDTH / 2, 106 mptr->pixel.y + CELL_HEIGHT / 2); 107 mptr->type = 5; 108 } 109 /*}}}*/ 110 else if(mptr->type == 6) 111 /*{{{ diamond*/ 112 { 113 /*{{{ new image?*/ 114 if(!mptr->cycle) 115 { 116 mptr->cycle = DIAMOND_CYCLES; 117 mptr->image++; 118 if(mptr->image == DIAMOND_IMAGES) 119 mptr->image = 0; 120 } 121 /*}}}*/ 122 mptr->cycle--; 123 if(!mptr->count--) 124 { 125 global.diamond = 0; 126 mptr->type = 5; 127 } 128 if(mptr->count == DIAMOND_GHOSTING) 129 mptr->ghosting = GHOSTING; 130 if(!mptr->stop) 131 move_diamond(mptr, BOARDCELL(mptr->cell.x, mptr->cell.y)); 132 } 133 /*}}}*/ 134 else if(global.state != 4) 135 { 136 CELL *cptr; 137 138 cptr = BOARDCELL(mptr->cell.x, mptr->cell.y); 139 assert(cptr->visit); 140 /*{{{ new image?*/ 141 if(!mptr->cycle) 142 { 143 mptr->cycle = MONSTER_CYCLES; 144 mptr->image++; 145 if(mptr->image == MONSTER_IMAGES) 146 mptr->image = 0; 147 } 148 /*}}}*/ 149 if((!mptr->count || mptr->type & 2) && !mptr->pause) 150 mptr->cycle--; 151 /*{{{ set nearest and farthest*/ 152 if(mptr->type & 2 || global.state != 2) 153 { 154 if(nearest > cptr->distance) 155 nearest = cptr->distance; 156 if(farthest < cptr->distance) 157 farthest = cptr->distance; 158 } 159 /*}}}*/ 160 if(mptr->type & 2 && !mptr->chew) 161 /*{{{ xtra or drone*/ 162 { 163 if(monster.delay && mptr->type == 2 && global.state == 2 && 164 (mptr->cell.y || mptr->offset.y >= 0) && 165 !(mptr->offset.x % VEL_X)) 166 /*{{{ give birth*/ 167 { 168 monster.delay--; 169 if(!monster.delay && monster.den) 170 { 171 monster.delay = XTRA_BIRTH_DELAY; 172 monster.den--; 173 spawn_monster(2, 3, mptr->dir, mptr->face, 174 mptr->cell.x, mptr->cell.y, 175 mptr->offset.x, mptr->offset.y); 176 monster.drones++; 177 i++; 178 } 179 } 180 /*}}}*/ 181 else 182 { 183 unsigned valid; 184 185 if(extra.escape == 2 && mptr->pixel.y < PIXELY(0, 0)) 186 valid = mptr->offset.y == -(CELL_HEIGHT + GAP_HEIGHT) ? 187 0x0 : 0x1; 188 else 189 { 190 valid = valid_directions(mptr, cptr); 191 /*{{{ near an apple?*/ 192 { 193 unsigned i; 194 APPLE *aptr; 195 int x, y; 196 197 x = mptr->pixel.x; 198 y = mptr->pixel.y; 199 for(aptr = apple.list, i = apple.apples; i--; aptr++) 200 { 201 if(!aptr->monsters && aptr->state < 3 && 202 !aptr->chewed && 203 INRANGE(aptr->pixel.x - x, VEL_X - CELL_WIDTH, 204 CELL_WIDTH - VEL_X + 1) && 205 INRANGE(aptr->pixel.y - y, VEL_Y - CELL_HEIGHT, 206 CELL_HEIGHT - VEL_Y + 1)) 207 { 208 if((mptr->dir & 2 ? 209 INRANGE(aptr->pixel.x - x, 210 -VEL_X, VEL_X + 1) : 211 INRANGE(aptr->pixel.x - x, 212 -VEL_X * 3, VEL_X * 3 + 1)) && 213 INRANGE(aptr->pixel.y - y, -VEL_Y, 214 aptr->state == 2 ? 215 VEL_Y + APPLE_VEL_Y + 1 : VEL_Y + 1) && 216 (aptr->state < 2 || !mptr->dir || 217 aptr->pixel.y >= y)) 218 { 219 mptr->chew = 1; 220 aptr->chewed = 1; 221 } 222 else 223 { 224 if(mptr->dir != 0 && valid & 0x2 && 225 aptr->pixel.y > y) 226 valid = 0x2; 227 else if(mptr->dir != 1 && valid & 0x1 && 228 aptr->pixel.y < y) 229 valid = 0x1; 230 else if(mptr->dir != 2 && valid & 0x8 && 231 aptr->pixel.x > x) 232 valid = 0x8; 233 else if(mptr->dir != 3 && valid & 0x4 && 234 aptr->pixel.x < x) 235 valid = 0x4; 236 } 237 break; 238 } 239 } 240 } 241 /*}}}*/ 242 } 243 if(mptr->offset.x || mptr->offset.y) 244 /* EMPTY */; 245 else if(extra.escape == 2) 246 mptr->fast = 0; 247 else if(global.state == 3) 248 mptr->fast = 1; 249 if(!valid) 250 { 251 mptr->type = 5; 252 extra.escape = 0; 253 extra.count = FRAMES_PER_SECOND - 1; 254 draw_extra(); 255 } 256 else 257 /*{{{ pick a direction*/ 258 { 259 unsigned temp; 260 261 if(player.ball.state == 1 && cptr->ball) 262 /*{{{ run away*/ 263 { 264 temp = 0; 265 if(mptr->offset.y <= 0 && 266 cptr[-CELL_STRIDE].ball < cptr->ball) 267 temp |= 0x1; 268 if(mptr->offset.y >= 0 && 269 cptr[CELL_STRIDE].ball < cptr->ball) 270 temp |= 0x2; 271 if(mptr->offset.x <= 0 && 272 cptr[-1].ball < cptr->ball) 273 temp |= 0x4; 274 if(mptr->offset.x >= 0 && 275 cptr[1].ball < cptr->ball) 276 temp |= 0x8; 277 if(temp & valid) 278 valid &= temp | (temp << 4); 279 } 280 /*}}}*/ 281 temp = valid & (~(0x11 << (mptr->dir ^ 1))); 282 if(mptr->type == 2) 283 /*{{{ xtra*/ 284 { 285 if((player.ball.state != 0) != mptr->gomunch) 286 temp = valid; 287 if(player.ball.state || 288 (global.state == 2 ? 289 mptr->count == monster.farthest : 290 mptr->count != monster.nearest)) 291 /*{{{ go towards*/ 292 { 293 if(extra.escape == 2) 294 temp &= 0xF; 295 if(temp & 0xF0) 296 valid = temp >> 4; 297 else if(temp) 298 valid = temp; 299 else 300 valid &= 0xF; 301 } 302 /*}}}*/ 303 else 304 /*{{{ run away*/ 305 { 306 unsigned suess; 307 308 suess = (temp ^ (temp >> 4)) & 0xF; 309 if(suess) 310 valid = suess; 311 else if(temp & 0xF) 312 valid = temp & 0xF; 313 else 314 valid &= 0xF; 315 } 316 /*}}}*/ 317 if(extra.escape == 2) 318 { 319 if(mptr->pixel.y <= PIXELY(0, 0) && 320 mptr->pixel.x == 321 PIXELX(4, extra.select * XTRA_SPACING)) 322 valid = 0x1; 323 else 324 /*{{{ run home*/ 325 { 326 unsigned preferred; 327 328 preferred = run_home(mptr, cptr); 329 if(preferred & valid) 330 valid &= preferred; 331 } 332 /*}}}*/ 333 } 334 } 335 /*}}}*/ 336 else 337 /*{{{ drone*/ 338 { 339 if(temp & 0xF0) 340 valid = temp >> 4; 341 else if(temp) 342 valid = temp; 343 else if(valid & 0xF0) 344 valid >>= 4; 345 else 346 valid &= 0xF; 347 } 348 /*}}}*/ 349 valid = choose_direction(valid); 350 if(mptr->pixel.y == PIXELY(0, 0) && mptr->dir == 1) 351 { 352 int x; 353 354 x = (mptr->offset.x + (valid & 1 ? 0 : 3)) / 355 VEL_X * VEL_X; 356 mptr->pixel.x += x - mptr->offset.x; 357 mptr->offset.x = x; 358 } 359 if(valid != mptr->dir) 360 { 361 mptr->dir = valid; 362 new_face(mptr); 363 } 364 mptr->count = cptr->distance; 365 cptr = move_movable(mptr, cptr); 366 if(mptr->pixel.y >= PIXELY(0, 0)) 367 /*{{{ walked into apple?*/ 368 { 369 unsigned i; 370 APPLE *aptr; 371 int x, y; 372 int width, height; 373 374 x = mptr->pixel.x; 375 y = mptr->pixel.y; 376 /*{{{ set offset*/ 377 switch(mptr->dir) 378 { 379 /*{{{ case 0:*/ 380 case 0: 381 { 382 x -= VEL_X - 1; 383 y -= APPLE_VEL_Y - 1; 384 width = VEL_X * 2 - 1; 385 height = VEL_Y + APPLE_VEL_Y * 2 - 1; 386 break; 387 } 388 /*}}}*/ 389 /*{{{ case 1:*/ 390 case 1: 391 { 392 x -= VEL_X - 1; 393 width = VEL_X * 2 - 1; 394 height = VEL_Y + APPLE_VEL_Y; 395 break; 396 } 397 /*}}}*/ 398 /*{{{ case 2:*/ 399 case 2: 400 { 401 x -= VEL_X + APPLE_VEL_X - 1; 402 y -= VEL_Y - 1; 403 width = (VEL_X + APPLE_VEL_X) * 2 - 1; 404 height = APPLE_VEL_Y + VEL_Y; 405 break; 406 } 407 /*}}}*/ 408 /*{{{ case 3:*/ 409 case 3: 410 { 411 x -= VEL_X + APPLE_VEL_X - 1; 412 y -= VEL_Y - 1; 413 width = (VEL_X + APPLE_VEL_X) * 2 - 1; 414 height = APPLE_VEL_Y + VEL_Y; 415 break; 416 } 417 /*}}}*/ 418 /*{{{ default: inhibit optimizer warning*/ 419 default: 420 { 421 width = height = 0; 422 break; 423 } 424 /*}}}*/ 425 } 426 /*}}}*/ 427 for(aptr = apple.list, i = apple.apples; i--; aptr++) 428 { 429 if(aptr->state < 3 && !aptr->chewed && 430 INRANGE(aptr->pixel.x - x, 0, width) && 431 INRANGE(aptr->pixel.y - y, 0, height)) 432 { 433 if(aptr->monsters) 434 { 435 assert(aptr->list && aptr->state == 2); 436 mptr->list = aptr->list; 437 aptr->list = mptr; 438 squish_monster(mptr); 439 mptr->pixel.y += 440 CELL_HEIGHT - CELL_HEIGHT / 4; 441 aptr->monsters++; 442 } 443 else 444 { 445 mptr->chew = 1; 446 aptr->chewed = 1; 447 } 448 break; 449 } 450 } 451 } 452 /*}}}*/ 453 /*{{{ go home adjust*/ 454 if(extra.escape == 2 && mptr->type == 2 && 455 mptr->pixel.y == PIXELY(0, 0) && mptr->dir & 2) 456 { 457 int x; 458 459 x = PIXELX(4, extra.select * XTRA_SPACING) - 460 mptr->pixel.x; 461 if(mptr->dir & 1 ? x < 0 && x > -VEL_X : 462 x > 0 && x < VEL_X) 463 { 464 mptr->pixel.x += x; 465 mptr->offset.x += x; 466 } 467 } 468 /*}}}*/ 469 mptr->gomunch = player.ball.state != 0; 470 } 471 /*}}}*/ 472 } 473 } 474 /*}}}*/ 475 else 476 /*{{{ normal or muncher or chewing*/ 477 { 478 if(global.state == 2 && !mptr->push && !mptr->chew) 479 { 480 if(mptr->count) 481 mptr->count--; 482 else 483 mptr->count = 1; 484 } 485 else 486 { 487 unsigned valid; 488 unsigned pause; 489 490 pause = 0; 491 if(mptr->chew == 1) 492 /*{{{ chewing*/ 493 { 494 mptr->chew = 2; 495 mptr->count = CHOMP_DELAY; 496 mptr->image = 0; 497 mptr->cycle = MONSTER_CYCLES - 1; 498 } 499 /*}}}*/ 500 valid = valid_directions(mptr, cptr); 501 if(mptr->type || mptr->cont) 502 /* EMPTY */; 503 else if((mptr->pause || mptr->stop) && 504 chaotic() < (mptr->dir & 2 ? 0 : (0x10 << mptr->dir) & 505 valid ? global.screen / STOP_TOGGLE_CONT_NEAR : 506 STOP_TOGGLE_CONT_STOP) + STOP_TOGGLE_CONT_PEDESTAL + 507 global.screen / STOP_TOGGLE_CONT_SCREEN_SCALE) 508 /*{{{ set cont & turn round*/ 509 { 510 mptr->cont = 1; 511 mptr->dir ^= 1; 512 new_face(mptr); 513 } 514 /*}}}*/ 515 else if(!cptr->distance) 516 mptr->cont = 1; 517 if(mptr->push) 518 /*{{{ disable left or right*/ 519 { 520 if(mptr->push < 0) 521 valid &= 0x77; 522 else 523 valid &= 0xBB; 524 if(mptr->offset.y >= 0) 525 { 526 if(valid & 0x2) 527 { 528 valid &= ~0x11; 529 mptr->cont = 1; 530 } 531 } 532 else 533 { 534 if(valid & 0x1) 535 { 536 valid &= ~0x22; 537 mptr->cont = 1; 538 } 539 } 540 } 541 /*}}}*/ 542 else if(mptr->count) 543 pause = 1; 544 else if(mptr->pause || mptr->stop) 545 /*{{{ test go munch or turn round*/ 546 { 547 if(!mptr->type) 548 { 549 if(chaotic() < GO_MUNCH_PROB * global.difficulty) 550 mptr->gomunch = 1; 551 } 552 else if(mptr->stop || chaotic() < PUSH_TURN_PROB) 553 { 554 mptr->dir ^= 1; 555 new_face(mptr); 556 mptr->count = GO_MUNCH_DELAY; 557 } 558 valid = 0; 559 mptr->stop = 0; 560 mptr->pause = 0; 561 } 562 /*}}}*/ 563 else if(!mptr->offset.x && !mptr->offset.y) 564 /*{{{ intersection stuff*/ 565 { 566 mptr->fast = !mptr->type && global.state == 3; 567 if(mptr->gomunch || (!cptr->distance && 568 !(valid & 1 << mptr->dir) && 569 chaotic() < TRAPPED_MUNCH_PROB)) 570 /*{{{ start munching?*/ 571 { 572 unsigned temp; 573 574 mptr->panic = 0; 575 temp = valid & 0xF; 576 if(!mptr->cell.y) 577 temp |= 0x1; 578 else if(mptr->cell.y == CELLS_DOWN - 1) 579 temp |= 0x2; 580 if(!mptr->cell.x) 581 temp |= 0x4; 582 else if(mptr->cell.x == CELLS_ACROSS - 1) 583 temp |= 0x8; 584 if(temp != 0xF) 585 { 586 mptr->type = 1; 587 mptr->count = GO_MUNCH_DELAY; 588 mptr->gomunch = 0; 589 } 590 } 591 /*}}}*/ 592 else if(mptr->type) 593 /*{{{ stop munching?*/ 594 { 595 int temp; 596 597 temp = valid & 0xF; 598 if((temp & -temp) != temp && (temp == 0xF || 599 chaotic() >= MUNCH_CONT_PEDESTAL + 600 global.screen / MUNCH_CONT_SCREEN_SCALE)) 601 { 602 mptr->type = 0; 603 mptr->count = STOP_MUNCH_DELAY; 604 valid = 0; 605 } 606 } 607 /*}}}*/ 608 else if(!mptr->type) 609 /*{{{ cont & gomunch stuff*/ 610 { 611 if(chaotic() < GO_MUNCH_PROB * global.difficulty) 612 mptr->gomunch = 1; 613 if(mptr->cont) 614 { 615 if(chaotic() < CLEAR_CONT_PEDESTAL + 616 global.visited / CLEAR_CONT_VISIT_SCALE + 617 (monster.den ? 0 : global.screen / 618 (monster.normals * monster.normals) * 619 CLEAR_CONT_MONSTER_SCALE)) 620 mptr->cont = 0; 621 } 622 else 623 { 624 if(chaotic() < SET_CONT_PEDESTAL) 625 mptr->cont = 1; 626 } 627 } 628 /*}}}*/ 629 } 630 /*}}}*/ 631 if(mptr->count) 632 mptr->count--; 633 if(pause) 634 /* EMPTY */; 635 else if(mptr->type == 1) 636 /*{{{ move the muncher*/ 637 { 638 if(mptr->offset.x || mptr->offset.y) 639 /*{{{ carry on*/ 640 { 641 CELL *nptr; 642 643 nptr = move_muncher(mptr); 644 if(nptr) 645 { 646 cptr = nptr; 647 if(nptr->sprite == SPRITE_CHERRY) 648 { 649 global.cherries--; 650 nptr->sprite = 0; 651 } 652 } 653 } 654 /*}}}*/ 655 else 656 /*{{{ pick new direction*/ 657 { 658 int temp; 659 660 temp = ~valid & 0xF; 661 if(!mptr->cell.y) 662 temp &= 0xE; 663 else if(mptr->cell.y == CELLS_DOWN - 1) 664 temp &= 0xD; 665 if(!mptr->cell.x) 666 temp &= 0xB; 667 else if(mptr->cell.x == CELLS_ACROSS - 1) 668 temp &= 0x7; 669 if(!temp) 670 temp = valid & 0xF; 671 if(mptr->cell.x < monster.list[0].cell.x) 672 valid = 0x8; 673 else if(mptr->cell.x > monster.list[0].cell.x) 674 valid = 0x4; 675 else 676 valid = 0; 677 if(!(valid & temp)) 678 { 679 if(mptr->pixel.y < monster.list[0].pixel.y) 680 valid = 0x2; 681 else if(mptr->pixel.y > monster.list[0].pixel.y) 682 valid = 0x1; 683 if(!(valid & temp)) 684 valid = temp; 685 } 686 assert(valid); 687 for(temp = 0; !(valid & 1); temp++) 688 valid >>= 1; 689 if(temp != mptr->dir) 690 { 691 mptr->dir = temp; 692 new_face(mptr); 693 } 694 move_muncher(mptr); 695 } 696 /*}}}*/ 697 } 698 /*}}}*/ 699 else if(valid) 700 /*{{{ pick a direction*/ 701 { 702 unsigned temp; 703 704 if(mptr->chew) 705 valid &= 0xF; 706 else if(mptr->panic) 707 /*{{{ panic mode*/ 708 { 709 temp = valid & ((1 << (mptr->dir ^ 1)) ^ 0xF); 710 if(mptr->offset.x < VEL_X * 4 - CELL_WIDTH && 711 valid & 0x8) 712 valid = 0x8; 713 else if(mptr->offset.x > CELL_WIDTH - VEL_X * 4 && 714 valid & 0x4) 715 valid = 0x4; 716 else if(temp & 0xC) 717 valid = temp & 0xC; 718 else if(valid & 0xC) 719 valid &= 0xC; 720 else if(valid & 0x2 && (mptr->dir == 1 || 721 mptr->offset.y < VEL_Y - CELL_HEIGHT / 2)) 722 valid = 0x2; 723 else if(valid & 1) 724 valid = 0x1; 725 else 726 valid &= 0xF; 727 mptr->panic++; 728 if(mptr->panic > PANIC_COUNT) 729 mptr->panic = 0; 730 } 731 /*}}}*/ 732 else 733 { 734 if(player.ball.state == 1 && cptr->ball) 735 /*{{{ run away*/ 736 { 737 temp = 0; 738 if(mptr->offset.y <= 0 && 739 cptr[-CELL_STRIDE].ball < cptr->ball) 740 temp |= 0x1; 741 if(mptr->offset.y >= 0 && 742 cptr[CELL_STRIDE].ball < cptr->ball) 743 temp |= 0x2; 744 if(mptr->offset.x <= 0 && 745 cptr[-1].ball < cptr->ball) 746 temp |= 0x4; 747 if(mptr->offset.x >= 0 && 748 cptr[1].ball < cptr->ball) 749 temp |= 0x8; 750 if(temp & valid) 751 valid &= temp | (temp << 4); 752 } 753 /*}}}*/ 754 if(mptr->cont || mptr->gomunch) 755 /*{{{ continue mode*/ 756 { 757 valid &= 0xF; 758 temp = valid & ~(1 << (mptr->dir ^ 1)); 759 if(temp) 760 valid = temp; 761 } 762 /*}}}*/ 763 else if(valid & 0xF0) 764 valid = valid & valid >> 4; 765 } 766 valid = choose_direction(valid); 767 temp = mptr->dir; 768 if(valid != mptr->dir) 769 { 770 mptr->dir = valid; 771 if(mptr->push && (valid ^ temp) != 1) 772 { 773 mptr->push = 0; 774 mptr->cont = 1; 775 } 776 new_face(mptr); 777 } 778 if(!apple_stop(mptr, cptr)) 779 cptr = move_movable(mptr, cptr); 780 if(mptr->push) 781 { 782 mptr->dir = temp; 783 mptr->push = 0; 784 } 785 } 786 /*}}}*/ 787 if(!mptr->count) 788 mptr->chew = 0; 789 } 790 } 791 /*}}}*/ 792 } 793 } 794 monster.nearest = nearest; 795 monster.farthest = farthest; 796 return; 797 } 798 /*}}}*/ 799 /*{{{ void new_xtra()*/ 800 extern VOIDFUNC new_xtra FUNCARGVOID 801 /* 802 * increment the extra monster, and draw it up 803 */ 804 { 805 static int direction = 1; 806 807 draw_extra_letter(extra.select); 808 if(direction < 0 ? extra.select == 0 : extra.select == 4) 809 direction = -direction; 810 extra.select += direction; 811 create_xtra_monster(extra.select); 812 extra.count = extra.got & (1 << extra.select) ? 813 XTRA_GOT_DELAY - 1 : XTRA_NEW_DELAY - 1; 814 draw_extra(); 815 return; 816 } 817 /*}}}*/ 818 /*{{{ MONSTER *spawn_monster(insert, type, dir, face, cx, cy, ox, oy)*/ 819 extern MONSTER *spawn_monster 820 FUNCARG((insert, type, dir, face, cx, cy, ox, oy), 821 unsigned insert /* where to insert in list (0 for end) */ 822 ARGSEP unsigned type /* type of monster 0-4 */ 823 ARGSEP unsigned dir /* direction 0-3 */ 824 ARGSEP unsigned face /* face 0-5 */ 825 ARGSEP int cx /* cell x */ 826 ARGSEP int cy /* cell y */ 827 ARGSEP int ox /* offset x */ 828 ARGSEP int oy /* offset y */ 829 ) 830 /* 831 * create a new monster onto the monster list 832 * if insert != 0 the insert the monster at that point on the 833 * list, adjusting the monster chains appropriately 834 * returns a pointer to the new monster 835 */ 836 { 837 MONSTER *mptr; 838 839 assert(monster.monsters != MONSTERS); 840 assert((!(ox % VEL_X) || (oy < 0 && !cy)) && !(oy % VEL_Y)); 841 if(insert) 842 { 843 MONSTER *sptr; 844 APPLE *aptr; 845 unsigned ix; 846 847 assert(insert <= monster.monsters); 848 mptr = &monster.list[insert]; 849 for(sptr = &monster.list[monster.monsters]; sptr-- != mptr;) 850 { 851 if(sptr->list && sptr->list >= mptr) 852 sptr->list++; 853 memcpy(sptr + 1, sptr, sizeof(MONSTER)); 854 } 855 for(aptr = apple.list, ix = apple.apples; ix--; aptr++) 856 if(aptr->list && aptr->list >= mptr) 857 aptr->list++; 858 monster.monsters++; 859 } 860 else 861 mptr = &monster.list[monster.monsters++]; 862 mptr->dir = dir; 863 mptr->type = type; 864 mptr->face = face; 865 mptr->push = 0; 866 mptr->gomunch = mptr->cont = mptr->chew = mptr->pause = mptr->stop = 0; 867 mptr->panic = mptr->shot = mptr->squished = 0; 868 mptr->fast = mptr->pushing = 0; 869 mptr->ghosting = 0; 870 mptr->count = 0; 871 mptr->cell.x = cx; 872 mptr->cell.y = cy; 873 mptr->offset.x = ox; 874 mptr->offset.y = oy; 875 mptr->old_pixel.x = mptr->pixel.x = PIXELX(cx, ox); 876 mptr->old_pixel.y = mptr->pixel.y = PIXELY(cy, oy); 877 mptr->list = NULL; 878 mptr->image = chaotic() % MONSTER_IMAGES; 879 mptr->cycle = chaotic() % MONSTER_CYCLES; 880 mptr->old_sprite = 0; 881 mptr->back = 0; 882 mptr->on = 1; 883 return mptr; 884 } 885 /*}}}*/ 886