WL_ACT1.C (16734B)
1 // WL_ACT1.C 2 3 #include "WL_DEF.H" 4 #pragma hdrstop 5 6 /* 7 ============================================================================= 8 9 STATICS 10 11 ============================================================================= 12 */ 13 14 15 statobj_t statobjlist[MAXSTATS],*laststatobj; 16 17 18 struct 19 { 20 int picnum; 21 stat_t type; 22 } statinfo[] = 23 { 24 {SPR_STAT_0}, // puddle spr1v 25 {SPR_STAT_1,block}, // Green Barrel " 26 {SPR_STAT_2,block}, // Table/chairs " 27 {SPR_STAT_3,block}, // Floor lamp " 28 {SPR_STAT_4}, // Chandelier " 29 {SPR_STAT_5,block}, // Hanged man " 30 {SPR_STAT_6,bo_alpo}, // Bad food " 31 {SPR_STAT_7,block}, // Red pillar " 32 // 33 // NEW PAGE 34 // 35 {SPR_STAT_8,block}, // Tree spr2v 36 {SPR_STAT_9}, // Skeleton flat " 37 {SPR_STAT_10,block}, // Sink " (SOD:gibs) 38 {SPR_STAT_11,block}, // Potted plant " 39 {SPR_STAT_12,block}, // Urn " 40 {SPR_STAT_13,block}, // Bare table " 41 {SPR_STAT_14}, // Ceiling light " 42 #ifndef SPEAR 43 {SPR_STAT_15}, // Kitchen stuff " 44 #else 45 {SPR_STAT_15,block}, // Gibs! 46 #endif 47 // 48 // NEW PAGE 49 // 50 {SPR_STAT_16,block}, // suit of armor spr3v 51 {SPR_STAT_17,block}, // Hanging cage " 52 {SPR_STAT_18,block}, // SkeletoninCage " 53 {SPR_STAT_19}, // Skeleton relax " 54 {SPR_STAT_20,bo_key1}, // Key 1 " 55 {SPR_STAT_21,bo_key2}, // Key 2 " 56 {SPR_STAT_22,block}, // stuff (SOD:gibs) 57 {SPR_STAT_23}, // stuff 58 // 59 // NEW PAGE 60 // 61 {SPR_STAT_24,bo_food}, // Good food spr4v 62 {SPR_STAT_25,bo_firstaid}, // First aid " 63 {SPR_STAT_26,bo_clip}, // Clip " 64 {SPR_STAT_27,bo_machinegun}, // Machine gun " 65 {SPR_STAT_28,bo_chaingun}, // Gatling gun " 66 {SPR_STAT_29,bo_cross}, // Cross " 67 {SPR_STAT_30,bo_chalice}, // Chalice " 68 {SPR_STAT_31,bo_bible}, // Bible " 69 // 70 // NEW PAGE 71 // 72 {SPR_STAT_32,bo_crown}, // crown spr5v 73 {SPR_STAT_33,bo_fullheal}, // one up " 74 {SPR_STAT_34,bo_gibs}, // gibs " 75 {SPR_STAT_35,block}, // barrel " 76 {SPR_STAT_36,block}, // well " 77 {SPR_STAT_37,block}, // Empty well " 78 {SPR_STAT_38,bo_gibs}, // Gibs 2 " 79 {SPR_STAT_39,block}, // flag " 80 // 81 // NEW PAGE 82 // 83 #ifndef SPEAR 84 {SPR_STAT_40,block}, // Call Apogee spr7v 85 #else 86 {SPR_STAT_40}, // Red light 87 #endif 88 // 89 // NEW PAGE 90 // 91 {SPR_STAT_41}, // junk " 92 {SPR_STAT_42}, // junk " 93 {SPR_STAT_43}, // junk " 94 #ifndef SPEAR 95 {SPR_STAT_44}, // pots " 96 #else 97 {SPR_STAT_44,block}, // Gibs! 98 #endif 99 {SPR_STAT_45,block}, // stove " (SOD:gibs) 100 {SPR_STAT_46,block}, // spears " (SOD:gibs) 101 {SPR_STAT_47}, // vines " 102 // 103 // NEW PAGE 104 // 105 #ifdef SPEAR 106 {SPR_STAT_48,block}, // marble pillar 107 {SPR_STAT_49,bo_25clip}, // bonus 25 clip 108 {SPR_STAT_50,block}, // truck 109 {SPR_STAT_51,bo_spear}, // SPEAR OF DESTINY! 110 #endif 111 112 {SPR_STAT_26,bo_clip2}, // Clip " 113 {-1} // terminator 114 }; 115 116 /* 117 =============== 118 = 119 = InitStaticList 120 = 121 =============== 122 */ 123 124 void InitStaticList (void) 125 { 126 laststatobj = &statobjlist[0]; 127 } 128 129 130 131 /* 132 =============== 133 = 134 = SpawnStatic 135 = 136 =============== 137 */ 138 139 void SpawnStatic (int tilex, int tiley, int type) 140 { 141 laststatobj->shapenum = statinfo[type].picnum; 142 laststatobj->tilex = tilex; 143 laststatobj->tiley = tiley; 144 laststatobj->visspot = &spotvis[tilex][tiley]; 145 146 switch (statinfo[type].type) 147 { 148 case block: 149 (unsigned)actorat[tilex][tiley] = 1; // consider it a blocking tile 150 case dressing: 151 laststatobj->flags = 0; 152 break; 153 154 case bo_cross: 155 case bo_chalice: 156 case bo_bible: 157 case bo_crown: 158 case bo_fullheal: 159 if (!loadedgame) 160 gamestate.treasuretotal++; 161 162 case bo_firstaid: 163 case bo_key1: 164 case bo_key2: 165 case bo_key3: 166 case bo_key4: 167 case bo_clip: 168 case bo_25clip: 169 case bo_machinegun: 170 case bo_chaingun: 171 case bo_food: 172 case bo_alpo: 173 case bo_gibs: 174 case bo_spear: 175 laststatobj->flags = FL_BONUS; 176 laststatobj->itemnumber = statinfo[type].type; 177 break; 178 } 179 180 laststatobj++; 181 182 if (laststatobj == &statobjlist[MAXSTATS]) 183 Quit ("Too many static objects!\n"); 184 } 185 186 187 /* 188 =============== 189 = 190 = PlaceItemType 191 = 192 = Called during game play to drop actors' items. It finds the proper 193 = item number based on the item type (bo_???). If there are no free item 194 = spots, nothing is done. 195 = 196 =============== 197 */ 198 199 void PlaceItemType (int itemtype, int tilex, int tiley) 200 { 201 int type; 202 statobj_t *spot; 203 204 // 205 // find the item number 206 // 207 for (type=0 ; ; type++) 208 { 209 if (statinfo[type].picnum == -1) // end of list 210 Quit ("PlaceItemType: couldn't find type!"); 211 if (statinfo[type].type == itemtype) 212 break; 213 } 214 215 // 216 // find a spot in statobjlist to put it in 217 // 218 for (spot=&statobjlist[0] ; ; spot++) 219 { 220 if (spot==laststatobj) 221 { 222 if (spot == &statobjlist[MAXSTATS]) 223 return; // no free spots 224 laststatobj++; // space at end 225 break; 226 } 227 228 if (spot->shapenum == -1) // -1 is a free spot 229 break; 230 } 231 // 232 // place it 233 // 234 spot->shapenum = statinfo[type].picnum; 235 spot->tilex = tilex; 236 spot->tiley = tiley; 237 spot->visspot = &spotvis[tilex][tiley]; 238 spot->flags = FL_BONUS; 239 spot->itemnumber = statinfo[type].type; 240 } 241 242 243 244 /* 245 ============================================================================= 246 247 DOORS 248 249 doorobjlist[] holds most of the information for the doors 250 251 doorposition[] holds the amount the door is open, ranging from 0 to 0xffff 252 this is directly accessed by AsmRefresh during rendering 253 254 The number of doors is limited to 64 because a spot in tilemap holds the 255 door number in the low 6 bits, with the high bit meaning a door center 256 and bit 6 meaning a door side tile 257 258 Open doors conect two areas, so sounds will travel between them and sight 259 will be checked when the player is in a connected area. 260 261 Areaconnect is incremented/decremented by each door. If >0 they connect 262 263 Every time a door opens or closes the areabyplayer matrix gets recalculated. 264 An area is true if it connects with the player's current spor. 265 266 ============================================================================= 267 */ 268 269 #define DOORWIDTH 0x7800 270 #define OPENTICS 300 271 272 doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; 273 int doornum; 274 275 unsigned doorposition[MAXDOORS]; // leading edge of door 0=closed 276 // 0xffff = fully open 277 278 byte far areaconnect[NUMAREAS][NUMAREAS]; 279 280 boolean areabyplayer[NUMAREAS]; 281 282 283 /* 284 ============== 285 = 286 = ConnectAreas 287 = 288 = Scans outward from playerarea, marking all connected areas 289 = 290 ============== 291 */ 292 293 void RecursiveConnect (int areanumber) 294 { 295 int i; 296 297 for (i=0;i<NUMAREAS;i++) 298 { 299 if (areaconnect[areanumber][i] && !areabyplayer[i]) 300 { 301 areabyplayer[i] = true; 302 RecursiveConnect (i); 303 } 304 } 305 } 306 307 308 void ConnectAreas (void) 309 { 310 memset (areabyplayer,0,sizeof(areabyplayer)); 311 areabyplayer[player->areanumber] = true; 312 RecursiveConnect (player->areanumber); 313 } 314 315 316 void InitAreas (void) 317 { 318 memset (areabyplayer,0,sizeof(areabyplayer)); 319 areabyplayer[player->areanumber] = true; 320 } 321 322 323 324 /* 325 =============== 326 = 327 = InitDoorList 328 = 329 =============== 330 */ 331 332 void InitDoorList (void) 333 { 334 memset (areabyplayer,0,sizeof(areabyplayer)); 335 _fmemset (areaconnect,0,sizeof(areaconnect)); 336 337 lastdoorobj = &doorobjlist[0]; 338 doornum = 0; 339 } 340 341 342 /* 343 =============== 344 = 345 = SpawnDoor 346 = 347 =============== 348 */ 349 350 void SpawnDoor (int tilex, int tiley, boolean vertical, int lock) 351 { 352 int areanumber; 353 unsigned far *map; 354 355 if (doornum==64) 356 Quit ("64+ doors on level!"); 357 358 doorposition[doornum] = 0; // doors start out fully closed 359 lastdoorobj->tilex = tilex; 360 lastdoorobj->tiley = tiley; 361 lastdoorobj->vertical = vertical; 362 lastdoorobj->lock = lock; 363 lastdoorobj->action = dr_closed; 364 365 (unsigned)actorat[tilex][tiley] = doornum | 0x80; // consider it a solid wall 366 367 // 368 // make the door tile a special tile, and mark the adjacent tiles 369 // for door sides 370 // 371 tilemap[tilex][tiley] = doornum | 0x80; 372 map = mapsegs[0] + farmapylookup[tiley]+tilex; 373 if (vertical) 374 { 375 *map = *(map-1); // set area number 376 tilemap[tilex][tiley-1] |= 0x40; 377 tilemap[tilex][tiley+1] |= 0x40; 378 } 379 else 380 { 381 *map = *(map-mapwidth); // set area number 382 tilemap[tilex-1][tiley] |= 0x40; 383 tilemap[tilex+1][tiley] |= 0x40; 384 } 385 386 doornum++; 387 lastdoorobj++; 388 } 389 390 //=========================================================================== 391 392 /* 393 ===================== 394 = 395 = OpenDoor 396 = 397 ===================== 398 */ 399 400 void OpenDoor (int door) 401 { 402 if (doorobjlist[door].action == dr_open) 403 doorobjlist[door].ticcount = 0; // reset open time 404 else 405 doorobjlist[door].action = dr_opening; // start it opening 406 } 407 408 409 /* 410 ===================== 411 = 412 = CloseDoor 413 = 414 ===================== 415 */ 416 417 void CloseDoor (int door) 418 { 419 int tilex,tiley,area; 420 objtype *check; 421 422 // 423 // don't close on anything solid 424 // 425 tilex = doorobjlist[door].tilex; 426 tiley = doorobjlist[door].tiley; 427 428 if (actorat[tilex][tiley]) 429 return; 430 431 if (player->tilex == tilex && player->tiley == tiley) 432 return; 433 434 if (doorobjlist[door].vertical) 435 { 436 if ( player->tiley == tiley ) 437 { 438 if ( ((player->x+MINDIST) >>TILESHIFT) == tilex ) 439 return; 440 if ( ((player->x-MINDIST) >>TILESHIFT) == tilex ) 441 return; 442 } 443 check = actorat[tilex-1][tiley]; 444 if (check && ((check->x+MINDIST) >> TILESHIFT) == tilex ) 445 return; 446 check = actorat[tilex+1][tiley]; 447 if (check && ((check->x-MINDIST) >> TILESHIFT) == tilex ) 448 return; 449 } 450 else if (!doorobjlist[door].vertical) 451 { 452 if (player->tilex == tilex) 453 { 454 if ( ((player->y+MINDIST) >>TILESHIFT) == tiley ) 455 return; 456 if ( ((player->y-MINDIST) >>TILESHIFT) == tiley ) 457 return; 458 } 459 check = actorat[tilex][tiley-1]; 460 if (check && ((check->y+MINDIST) >> TILESHIFT) == tiley ) 461 return; 462 check = actorat[tilex][tiley+1]; 463 if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley ) 464 return; 465 } 466 467 468 // 469 // play door sound if in a connected area 470 // 471 area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley] 472 +doorobjlist[door].tilex)-AREATILE; 473 if (areabyplayer[area]) 474 { 475 PlaySoundLocTile(CLOSEDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB 476 } 477 478 doorobjlist[door].action = dr_closing; 479 // 480 // make the door space solid 481 // 482 (unsigned)actorat[tilex][tiley] 483 = door | 0x80; 484 } 485 486 487 488 /* 489 ===================== 490 = 491 = OperateDoor 492 = 493 = The player wants to change the door's direction 494 = 495 ===================== 496 */ 497 498 void OperateDoor (int door) 499 { 500 int lock; 501 502 lock = doorobjlist[door].lock; 503 if (lock >= dr_lock1 && lock <= dr_lock4) 504 { 505 if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) ) 506 { 507 SD_PlaySound (NOWAYSND); // locked 508 return; 509 } 510 } 511 512 switch (doorobjlist[door].action) 513 { 514 case dr_closed: 515 case dr_closing: 516 OpenDoor (door); 517 break; 518 case dr_open: 519 case dr_opening: 520 CloseDoor (door); 521 break; 522 } 523 } 524 525 526 //=========================================================================== 527 528 /* 529 =============== 530 = 531 = DoorOpen 532 = 533 = Close the door after three seconds 534 = 535 =============== 536 */ 537 538 void DoorOpen (int door) 539 { 540 if ( (doorobjlist[door].ticcount += tics) >= OPENTICS) 541 CloseDoor (door); 542 } 543 544 545 546 /* 547 =============== 548 = 549 = DoorOpening 550 = 551 =============== 552 */ 553 554 void DoorOpening (int door) 555 { 556 int area1,area2; 557 unsigned far *map; 558 long position; 559 560 position = doorposition[door]; 561 if (!position) 562 { 563 // 564 // door is just starting to open, so connect the areas 565 // 566 map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] 567 +doorobjlist[door].tilex; 568 569 if (doorobjlist[door].vertical) 570 { 571 area1 = *(map+1); 572 area2 = *(map-1); 573 } 574 else 575 { 576 area1 = *(map-mapwidth); 577 area2 = *(map+mapwidth); 578 } 579 area1 -= AREATILE; 580 area2 -= AREATILE; 581 areaconnect[area1][area2]++; 582 areaconnect[area2][area1]++; 583 ConnectAreas (); 584 if (areabyplayer[area1]) 585 { 586 PlaySoundLocTile(OPENDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB 587 } 588 } 589 590 // 591 // slide the door by an adaptive amount 592 // 593 position += tics<<10; 594 if (position >= 0xffff) 595 { 596 // 597 // door is all the way open 598 // 599 position = 0xffff; 600 doorobjlist[door].ticcount = 0; 601 doorobjlist[door].action = dr_open; 602 actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0; 603 } 604 605 doorposition[door] = position; 606 } 607 608 609 /* 610 =============== 611 = 612 = DoorClosing 613 = 614 =============== 615 */ 616 617 void DoorClosing (int door) 618 { 619 int area1,area2,move; 620 unsigned far *map; 621 long position; 622 int tilex,tiley; 623 624 tilex = doorobjlist[door].tilex; 625 tiley = doorobjlist[door].tiley; 626 627 if ( ((unsigned)actorat[tilex][tiley] != (door | 0x80)) 628 || (player->tilex == tilex && player->tiley == tiley) ) 629 { // something got inside the door 630 OpenDoor (door); 631 return; 632 }; 633 634 position = doorposition[door]; 635 636 // 637 // slide the door by an adaptive amount 638 // 639 position -= tics<<10; 640 if (position <= 0) 641 { 642 // 643 // door is closed all the way, so disconnect the areas 644 // 645 position = 0; 646 647 doorobjlist[door].action = dr_closed; 648 649 map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] 650 +doorobjlist[door].tilex; 651 652 if (doorobjlist[door].vertical) 653 { 654 area1 = *(map+1); 655 area2 = *(map-1); 656 } 657 else 658 { 659 area1 = *(map-mapwidth); 660 area2 = *(map+mapwidth); 661 } 662 area1 -= AREATILE; 663 area2 -= AREATILE; 664 areaconnect[area1][area2]--; 665 areaconnect[area2][area1]--; 666 667 ConnectAreas (); 668 } 669 670 doorposition[door] = position; 671 } 672 673 674 675 676 /* 677 ===================== 678 = 679 = MoveDoors 680 = 681 = Called from PlayLoop 682 = 683 ===================== 684 */ 685 686 void MoveDoors (void) 687 { 688 int door; 689 690 if (gamestate.victoryflag) // don't move door during victory sequence 691 return; 692 693 for (door = 0 ; door < doornum ; door++) 694 switch (doorobjlist[door].action) 695 { 696 case dr_open: 697 DoorOpen (door); 698 break; 699 700 case dr_opening: 701 DoorOpening(door); 702 break; 703 704 case dr_closing: 705 DoorClosing(door); 706 break; 707 } 708 } 709 710 711 /* 712 ============================================================================= 713 714 PUSHABLE WALLS 715 716 ============================================================================= 717 */ 718 719 unsigned pwallstate; 720 unsigned pwallpos; // amount a pushable wall has been moved (0-63) 721 unsigned pwallx,pwally; 722 int pwalldir; 723 724 /* 725 =============== 726 = 727 = PushWall 728 = 729 =============== 730 */ 731 732 void PushWall (int checkx, int checky, int dir) 733 { 734 int oldtile; 735 736 if (pwallstate) 737 return; 738 739 740 oldtile = tilemap[checkx][checky]; 741 if (!oldtile) 742 return; 743 744 switch (dir) 745 { 746 case di_north: 747 if (actorat[checkx][checky-1]) 748 { 749 SD_PlaySound (NOWAYSND); 750 return; 751 } 752 (unsigned)actorat[checkx][checky-1] = 753 tilemap[checkx][checky-1] = oldtile; 754 break; 755 756 case di_east: 757 if (actorat[checkx+1][checky]) 758 { 759 SD_PlaySound (NOWAYSND); 760 return; 761 } 762 (unsigned)actorat[checkx+1][checky] = 763 tilemap[checkx+1][checky] = oldtile; 764 break; 765 766 case di_south: 767 if (actorat[checkx][checky+1]) 768 { 769 SD_PlaySound (NOWAYSND); 770 return; 771 } 772 (unsigned)actorat[checkx][checky+1] = 773 tilemap[checkx][checky+1] = oldtile; 774 break; 775 776 case di_west: 777 if (actorat[checkx-1][checky]) 778 { 779 SD_PlaySound (NOWAYSND); 780 return; 781 } 782 (unsigned)actorat[checkx-1][checky] = 783 tilemap[checkx-1][checky] = oldtile; 784 break; 785 } 786 787 gamestate.secretcount++; 788 pwallx = checkx; 789 pwally = checky; 790 pwalldir = dir; 791 pwallstate = 1; 792 pwallpos = 0; 793 tilemap[pwallx][pwally] |= 0xc0; 794 *(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0; // remove P tile info 795 796 SD_PlaySound (PUSHWALLSND); 797 } 798 799 800 801 /* 802 ================= 803 = 804 = MovePWalls 805 = 806 ================= 807 */ 808 809 void MovePWalls (void) 810 { 811 int oldblock,oldtile; 812 813 if (!pwallstate) 814 return; 815 816 oldblock = pwallstate/128; 817 818 pwallstate += tics; 819 820 if (pwallstate/128 != oldblock) 821 { 822 // block crossed into a new block 823 oldtile = tilemap[pwallx][pwally] & 63; 824 825 // 826 // the tile can now be walked into 827 // 828 tilemap[pwallx][pwally] = 0; 829 (unsigned)actorat[pwallx][pwally] = 0; 830 *(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE; 831 832 // 833 // see if it should be pushed farther 834 // 835 if (pwallstate>256) 836 { 837 // 838 // the block has been pushed two tiles 839 // 840 pwallstate = 0; 841 return; 842 } 843 else 844 { 845 switch (pwalldir) 846 { 847 case di_north: 848 pwally--; 849 if (actorat[pwallx][pwally-1]) 850 { 851 pwallstate = 0; 852 return; 853 } 854 (unsigned)actorat[pwallx][pwally-1] = 855 tilemap[pwallx][pwally-1] = oldtile; 856 break; 857 858 case di_east: 859 pwallx++; 860 if (actorat[pwallx+1][pwally]) 861 { 862 pwallstate = 0; 863 return; 864 } 865 (unsigned)actorat[pwallx+1][pwally] = 866 tilemap[pwallx+1][pwally] = oldtile; 867 break; 868 869 case di_south: 870 pwally++; 871 if (actorat[pwallx][pwally+1]) 872 { 873 pwallstate = 0; 874 return; 875 } 876 (unsigned)actorat[pwallx][pwally+1] = 877 tilemap[pwallx][pwally+1] = oldtile; 878 break; 879 880 case di_west: 881 pwallx--; 882 if (actorat[pwallx-1][pwally]) 883 { 884 pwallstate = 0; 885 return; 886 } 887 (unsigned)actorat[pwallx-1][pwally] = 888 tilemap[pwallx-1][pwally] = oldtile; 889 break; 890 } 891 892 tilemap[pwallx][pwally] = oldtile | 0xc0; 893 } 894 } 895 896 897 pwallpos = (pwallstate/2)&63; 898 899 } 900