WL_AGENT.C (22576B)
1 // WL_AGENT.C 2 3 #include "WL_DEF.H" 4 #pragma hdrstop 5 6 7 /* 8 ============================================================================= 9 10 LOCAL CONSTANTS 11 12 ============================================================================= 13 */ 14 15 #define MAXMOUSETURN 10 16 17 18 #define MOVESCALE 150l 19 #define BACKMOVESCALE 100l 20 #define ANGLESCALE 20 21 22 /* 23 ============================================================================= 24 25 GLOBAL VARIABLES 26 27 ============================================================================= 28 */ 29 30 31 32 // 33 // player state info 34 // 35 boolean running; 36 long thrustspeed; 37 38 unsigned plux,pluy; // player coordinates scaled to unsigned 39 40 int anglefrac; 41 int gotgatgun; // JR 42 43 objtype *LastAttacker; 44 45 /* 46 ============================================================================= 47 48 LOCAL VARIABLES 49 50 ============================================================================= 51 */ 52 53 54 void T_Player (objtype *ob); 55 void T_Attack (objtype *ob); 56 57 statetype s_player = {false,0,0,T_Player,NULL,NULL}; 58 statetype s_attack = {false,0,0,T_Attack,NULL,NULL}; 59 60 61 long playerxmove,playerymove; 62 63 struct atkinf 64 { 65 char tics,attack,frame; // attack is 1 for gun, 2 for knife 66 } attackinfo[4][14] = 67 68 { 69 { {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, 70 { {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, 71 { {6,0,1},{6,1,2},{6,3,3},{6,-1,4} }, 72 { {6,0,1},{6,1,2},{6,4,3},{6,-1,4} }, 73 }; 74 75 76 int strafeangle[9] = {0,90,180,270,45,135,225,315,0}; 77 78 void DrawWeapon (void); 79 void GiveWeapon (int weapon); 80 void GiveAmmo (int ammo); 81 82 //=========================================================================== 83 84 //---------- 85 86 void Attack (void); 87 void Use (void); 88 void Search (objtype *ob); 89 void SelectWeapon (void); 90 void SelectItem (void); 91 92 //---------- 93 94 boolean TryMove (objtype *ob); 95 void T_Player (objtype *ob); 96 97 void ClipMove (objtype *ob, long xmove, long ymove); 98 99 /* 100 ============================================================================= 101 102 CONTROL STUFF 103 104 ============================================================================= 105 */ 106 107 /* 108 ====================== 109 = 110 = CheckWeaponChange 111 = 112 = Keys 1-4 change weapons 113 = 114 ====================== 115 */ 116 117 void CheckWeaponChange (void) 118 { 119 int i,buttons; 120 121 if (!gamestate.ammo) // must use knife with no ammo 122 return; 123 124 for (i=wp_knife ; i<=gamestate.bestweapon ; i++) 125 if (buttonstate[bt_readyknife+i-wp_knife]) 126 { 127 gamestate.weapon = gamestate.chosenweapon = i; 128 DrawWeapon (); 129 return; 130 } 131 } 132 133 134 /* 135 ======================= 136 = 137 = ControlMovement 138 = 139 = Takes controlx,controly, and buttonstate[bt_strafe] 140 = 141 = Changes the player's angle and position 142 = 143 = There is an angle hack because when going 70 fps, the roundoff becomes 144 = significant 145 = 146 ======================= 147 */ 148 149 void ControlMovement (objtype *ob) 150 { 151 long oldx,oldy; 152 int angle,maxxmove; 153 int angleunits; 154 long speed; 155 156 thrustspeed = 0; 157 158 oldx = player->x; 159 oldy = player->y; 160 161 // 162 // side to side move 163 // 164 if (buttonstate[bt_strafe]) 165 { 166 // 167 // strafing 168 // 169 // 170 if (controlx > 0) 171 { 172 angle = ob->angle - ANGLES/4; 173 if (angle < 0) 174 angle += ANGLES; 175 Thrust (angle,controlx*MOVESCALE); // move to left 176 } 177 else if (controlx < 0) 178 { 179 angle = ob->angle + ANGLES/4; 180 if (angle >= ANGLES) 181 angle -= ANGLES; 182 Thrust (angle,-controlx*MOVESCALE); // move to right 183 } 184 } 185 else 186 { 187 // 188 // not strafing 189 // 190 anglefrac += controlx; 191 angleunits = anglefrac/ANGLESCALE; 192 anglefrac -= angleunits*ANGLESCALE; 193 ob->angle -= angleunits; 194 195 if (ob->angle >= ANGLES) 196 ob->angle -= ANGLES; 197 if (ob->angle < 0) 198 ob->angle += ANGLES; 199 200 } 201 202 // 203 // forward/backwards move 204 // 205 if (controly < 0) 206 { 207 Thrust (ob->angle,-controly*MOVESCALE); // move forwards 208 } 209 else if (controly > 0) 210 { 211 angle = ob->angle + ANGLES/2; 212 if (angle >= ANGLES) 213 angle -= ANGLES; 214 Thrust (angle,controly*BACKMOVESCALE); // move backwards 215 } 216 217 if (gamestate.victoryflag) // watching the BJ actor 218 return; 219 220 // 221 // calculate total move 222 // 223 playerxmove = player->x - oldx; 224 playerymove = player->y - oldy; 225 } 226 227 /* 228 ============================================================================= 229 230 STATUS WINDOW STUFF 231 232 ============================================================================= 233 */ 234 235 236 /* 237 ================== 238 = 239 = StatusDrawPic 240 = 241 ================== 242 */ 243 244 void StatusDrawPic (unsigned x, unsigned y, unsigned picnum) 245 { 246 unsigned temp; 247 248 temp = bufferofs; 249 bufferofs = 0; 250 251 bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH; 252 LatchDrawPic (x,y,picnum); 253 bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH; 254 LatchDrawPic (x,y,picnum); 255 bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH; 256 LatchDrawPic (x,y,picnum); 257 258 bufferofs = temp; 259 } 260 261 262 /* 263 ================== 264 = 265 = DrawFace 266 = 267 ================== 268 */ 269 270 void DrawFace (void) 271 { 272 if (gamestate.health) 273 { 274 #ifdef SPEAR 275 if (godmode) 276 StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe); 277 else 278 #endif 279 StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe); 280 } 281 else 282 { 283 #ifndef SPEAR 284 if (LastAttacker->obclass == needleobj) 285 StatusDrawPic (17,4,MUTANTBJPIC); 286 else 287 #endif 288 StatusDrawPic (17,4,FACE8APIC); 289 } 290 } 291 292 293 /* 294 =============== 295 = 296 = UpdateFace 297 = 298 = Calls draw face if time to change 299 = 300 =============== 301 */ 302 303 #define FACETICS 70 304 305 int facecount; 306 307 void UpdateFace (void) 308 { 309 310 if (SD_SoundPlaying() == GETGATLINGSND) 311 return; 312 313 facecount += tics; 314 if (facecount > US_RndT()) 315 { 316 gamestate.faceframe = (US_RndT()>>6); 317 if (gamestate.faceframe==3) 318 gamestate.faceframe = 1; 319 320 facecount = 0; 321 DrawFace (); 322 } 323 } 324 325 326 327 /* 328 =============== 329 = 330 = LatchNumber 331 = 332 = right justifies and pads with blanks 333 = 334 =============== 335 */ 336 337 void LatchNumber (int x, int y, int width, long number) 338 { 339 unsigned length,c; 340 char str[20]; 341 342 ltoa (number,str,10); 343 344 length = strlen (str); 345 346 while (length<width) 347 { 348 StatusDrawPic (x,y,N_BLANKPIC); 349 x++; 350 width--; 351 } 352 353 c= length <= width ? 0 : length-width; 354 355 while (c<length) 356 { 357 StatusDrawPic (x,y,str[c]-'0'+ N_0PIC); 358 x++; 359 c++; 360 } 361 } 362 363 364 /* 365 =============== 366 = 367 = DrawHealth 368 = 369 =============== 370 */ 371 372 void DrawHealth (void) 373 { 374 LatchNumber (21,16,3,gamestate.health); 375 } 376 377 378 /* 379 =============== 380 = 381 = TakeDamage 382 = 383 =============== 384 */ 385 386 void TakeDamage (int points,objtype *attacker) 387 { 388 LastAttacker = attacker; 389 390 if (gamestate.victoryflag) 391 return; 392 if (gamestate.difficulty==gd_baby) 393 points>>=2; 394 395 if (!godmode) 396 gamestate.health -= points; 397 398 if (gamestate.health<=0) 399 { 400 gamestate.health = 0; 401 playstate = ex_died; 402 killerobj = attacker; 403 } 404 405 StartDamageFlash (points); 406 407 gotgatgun=0; 408 409 DrawHealth (); 410 DrawFace (); 411 412 // 413 // MAKE BJ'S EYES BUG IF MAJOR DAMAGE! 414 // 415 #ifdef SPEAR 416 if (points > 30 && gamestate.health!=0 && !godmode) 417 { 418 StatusDrawPic (17,4,BJOUCHPIC); 419 facecount = 0; 420 } 421 #endif 422 423 } 424 425 426 /* 427 =============== 428 = 429 = HealSelf 430 = 431 =============== 432 */ 433 434 void HealSelf (int points) 435 { 436 gamestate.health += points; 437 if (gamestate.health>100) 438 gamestate.health = 100; 439 440 DrawHealth (); 441 gotgatgun = 0; // JR 442 DrawFace (); 443 } 444 445 446 //=========================================================================== 447 448 449 /* 450 =============== 451 = 452 = DrawLevel 453 = 454 =============== 455 */ 456 457 void DrawLevel (void) 458 { 459 #ifdef SPEAR 460 if (gamestate.mapon == 20) 461 LatchNumber (2,16,2,18); 462 else 463 #endif 464 LatchNumber (2,16,2,gamestate.mapon+1); 465 } 466 467 //=========================================================================== 468 469 470 /* 471 =============== 472 = 473 = DrawLives 474 = 475 =============== 476 */ 477 478 void DrawLives (void) 479 { 480 LatchNumber (14,16,1,gamestate.lives); 481 } 482 483 484 /* 485 =============== 486 = 487 = GiveExtraMan 488 = 489 =============== 490 */ 491 492 void GiveExtraMan (void) 493 { 494 if (gamestate.lives<9) 495 gamestate.lives++; 496 DrawLives (); 497 SD_PlaySound (BONUS1UPSND); 498 } 499 500 //=========================================================================== 501 502 /* 503 =============== 504 = 505 = DrawScore 506 = 507 =============== 508 */ 509 510 void DrawScore (void) 511 { 512 LatchNumber (6,16,6,gamestate.score); 513 } 514 515 /* 516 =============== 517 = 518 = GivePoints 519 = 520 =============== 521 */ 522 523 void GivePoints (long points) 524 { 525 gamestate.score += points; 526 while (gamestate.score >= gamestate.nextextra) 527 { 528 gamestate.nextextra += EXTRAPOINTS; 529 GiveExtraMan (); 530 } 531 DrawScore (); 532 } 533 534 //=========================================================================== 535 536 /* 537 ================== 538 = 539 = DrawWeapon 540 = 541 ================== 542 */ 543 544 void DrawWeapon (void) 545 { 546 StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon); 547 } 548 549 550 /* 551 ================== 552 = 553 = DrawKeys 554 = 555 ================== 556 */ 557 558 void DrawKeys (void) 559 { 560 if (gamestate.keys & 1) 561 StatusDrawPic (30,4,GOLDKEYPIC); 562 else 563 StatusDrawPic (30,4,NOKEYPIC); 564 565 if (gamestate.keys & 2) 566 StatusDrawPic (30,20,SILVERKEYPIC); 567 else 568 StatusDrawPic (30,20,NOKEYPIC); 569 } 570 571 572 573 /* 574 ================== 575 = 576 = GiveWeapon 577 = 578 ================== 579 */ 580 581 void GiveWeapon (int weapon) 582 { 583 GiveAmmo (6); 584 585 if (gamestate.bestweapon<weapon) 586 gamestate.bestweapon = gamestate.weapon 587 = gamestate.chosenweapon = weapon; 588 589 DrawWeapon (); 590 } 591 592 593 //=========================================================================== 594 595 /* 596 =============== 597 = 598 = DrawAmmo 599 = 600 =============== 601 */ 602 603 void DrawAmmo (void) 604 { 605 LatchNumber (27,16,2,gamestate.ammo); 606 } 607 608 609 /* 610 =============== 611 = 612 = GiveAmmo 613 = 614 =============== 615 */ 616 617 void GiveAmmo (int ammo) 618 { 619 if (!gamestate.ammo) // knife was out 620 { 621 if (!gamestate.attackframe) 622 { 623 gamestate.weapon = gamestate.chosenweapon; 624 DrawWeapon (); 625 } 626 } 627 gamestate.ammo += ammo; 628 if (gamestate.ammo > 99) 629 gamestate.ammo = 99; 630 DrawAmmo (); 631 } 632 633 //=========================================================================== 634 635 /* 636 ================== 637 = 638 = GiveKey 639 = 640 ================== 641 */ 642 643 void GiveKey (int key) 644 { 645 gamestate.keys |= (1<<key); 646 DrawKeys (); 647 } 648 649 650 651 /* 652 ============================================================================= 653 654 MOVEMENT 655 656 ============================================================================= 657 */ 658 659 660 /* 661 =================== 662 = 663 = GetBonus 664 = 665 =================== 666 */ 667 void GetBonus (statobj_t *check) 668 { 669 switch (check->itemnumber) 670 { 671 case bo_firstaid: 672 if (gamestate.health == 100) 673 return; 674 675 SD_PlaySound (HEALTH2SND); 676 HealSelf (25); 677 break; 678 679 case bo_key1: 680 case bo_key2: 681 case bo_key3: 682 case bo_key4: 683 GiveKey (check->itemnumber - bo_key1); 684 SD_PlaySound (GETKEYSND); 685 break; 686 687 case bo_cross: 688 SD_PlaySound (BONUS1SND); 689 GivePoints (100); 690 gamestate.treasurecount++; 691 break; 692 case bo_chalice: 693 SD_PlaySound (BONUS2SND); 694 GivePoints (500); 695 gamestate.treasurecount++; 696 break; 697 case bo_bible: 698 SD_PlaySound (BONUS3SND); 699 GivePoints (1000); 700 gamestate.treasurecount++; 701 break; 702 case bo_crown: 703 SD_PlaySound (BONUS4SND); 704 GivePoints (5000); 705 gamestate.treasurecount++; 706 break; 707 708 case bo_clip: 709 if (gamestate.ammo == 99) 710 return; 711 712 SD_PlaySound (GETAMMOSND); 713 GiveAmmo (8); 714 break; 715 case bo_clip2: 716 if (gamestate.ammo == 99) 717 return; 718 719 SD_PlaySound (GETAMMOSND); 720 GiveAmmo (4); 721 break; 722 723 #ifdef SPEAR 724 case bo_25clip: 725 if (gamestate.ammo == 99) 726 return; 727 728 SD_PlaySound (GETAMMOBOXSND); 729 GiveAmmo (25); 730 break; 731 #endif 732 733 case bo_machinegun: 734 SD_PlaySound (GETMACHINESND); 735 GiveWeapon (wp_machinegun); 736 break; 737 case bo_chaingun: 738 SD_PlaySound (GETGATLINGSND); 739 GiveWeapon (wp_chaingun); 740 741 StatusDrawPic (17,4,GOTGATLINGPIC); 742 facecount = 0; 743 gotgatgun = 1; 744 break; 745 746 case bo_fullheal: 747 SD_PlaySound (BONUS1UPSND); 748 HealSelf (99); 749 GiveAmmo (25); 750 GiveExtraMan (); 751 gamestate.treasurecount++; 752 break; 753 754 case bo_food: 755 if (gamestate.health == 100) 756 return; 757 758 SD_PlaySound (HEALTH1SND); 759 HealSelf (10); 760 break; 761 762 case bo_alpo: 763 if (gamestate.health == 100) 764 return; 765 766 SD_PlaySound (HEALTH1SND); 767 HealSelf (4); 768 break; 769 770 case bo_gibs: 771 if (gamestate.health >10) 772 return; 773 774 SD_PlaySound (SLURPIESND); 775 HealSelf (1); 776 break; 777 778 case bo_spear: 779 spearflag = true; 780 spearx = player->x; 781 speary = player->y; 782 spearangle = player->angle; 783 playstate = ex_completed; 784 } 785 786 StartBonusFlash (); 787 check->shapenum = -1; // remove from list 788 } 789 790 791 /* 792 =================== 793 = 794 = TryMove 795 = 796 = returns true if move ok 797 = debug: use pointers to optimize 798 =================== 799 */ 800 801 boolean TryMove (objtype *ob) 802 { 803 int xl,yl,xh,yh,x,y; 804 objtype *check; 805 long deltax,deltay; 806 807 xl = (ob->x-PLAYERSIZE) >>TILESHIFT; 808 yl = (ob->y-PLAYERSIZE) >>TILESHIFT; 809 810 xh = (ob->x+PLAYERSIZE) >>TILESHIFT; 811 yh = (ob->y+PLAYERSIZE) >>TILESHIFT; 812 813 // 814 // check for solid walls 815 // 816 for (y=yl;y<=yh;y++) 817 for (x=xl;x<=xh;x++) 818 { 819 check = actorat[x][y]; 820 if (check && check<objlist) 821 return false; 822 } 823 824 // 825 // check for actors 826 // 827 if (yl>0) 828 yl--; 829 if (yh<MAPSIZE-1) 830 yh++; 831 if (xl>0) 832 xl--; 833 if (xh<MAPSIZE-1) 834 xh++; 835 836 for (y=yl;y<=yh;y++) 837 for (x=xl;x<=xh;x++) 838 { 839 check = actorat[x][y]; 840 if (check > objlist 841 && (check->flags & FL_SHOOTABLE) ) 842 { 843 deltax = ob->x - check->x; 844 if (deltax < -MINACTORDIST || deltax > MINACTORDIST) 845 continue; 846 deltay = ob->y - check->y; 847 if (deltay < -MINACTORDIST || deltay > MINACTORDIST) 848 continue; 849 850 return false; 851 } 852 } 853 854 return true; 855 } 856 857 858 /* 859 =================== 860 = 861 = ClipMove 862 = 863 =================== 864 */ 865 866 void ClipMove (objtype *ob, long xmove, long ymove) 867 { 868 long basex,basey; 869 870 basex = ob->x; 871 basey = ob->y; 872 873 ob->x = basex+xmove; 874 ob->y = basey+ymove; 875 if (TryMove (ob)) 876 return; 877 878 if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL && 879 ob->x < (((long)(mapwidth-1))<<TILESHIFT) 880 && ob->y < (((long)(mapheight-1))<<TILESHIFT) ) 881 return; // walk through walls 882 883 if (!SD_SoundPlaying()) 884 SD_PlaySound (HITWALLSND); 885 886 ob->x = basex+xmove; 887 ob->y = basey; 888 if (TryMove (ob)) 889 return; 890 891 ob->x = basex; 892 ob->y = basey+ymove; 893 if (TryMove (ob)) 894 return; 895 896 ob->x = basex; 897 ob->y = basey; 898 } 899 900 //========================================================================== 901 902 /* 903 =================== 904 = 905 = VictoryTile 906 = 907 =================== 908 */ 909 910 void VictoryTile (void) 911 { 912 #ifndef SPEAR 913 SpawnBJVictory (); 914 #endif 915 916 gamestate.victoryflag = true; 917 } 918 919 920 /* 921 =================== 922 = 923 = Thrust 924 = 925 =================== 926 */ 927 928 void Thrust (int angle, long speed) 929 { 930 long xmove,ymove; 931 long slowmax; 932 unsigned offset; 933 934 935 // 936 // ZERO FUNNY COUNTER IF MOVED! 937 // 938 #ifdef SPEAR 939 if (speed) 940 funnyticount = 0; 941 #endif 942 943 thrustspeed += speed; 944 // 945 // moving bounds speed 946 // 947 if (speed >= MINDIST*2) 948 speed = MINDIST*2-1; 949 950 xmove = FixedByFrac(speed,costable[angle]); 951 ymove = -FixedByFrac(speed,sintable[angle]); 952 953 ClipMove(player,xmove,ymove); 954 955 player->tilex = player->x >> TILESHIFT; // scale to tile values 956 player->tiley = player->y >> TILESHIFT; 957 958 offset = farmapylookup[player->tiley]+player->tilex; 959 player->areanumber = *(mapsegs[0] + offset) -AREATILE; 960 961 if (*(mapsegs[1] + offset) == EXITTILE) 962 VictoryTile (); 963 } 964 965 966 /* 967 ============================================================================= 968 969 ACTIONS 970 971 ============================================================================= 972 */ 973 974 975 /* 976 =============== 977 = 978 = Cmd_Fire 979 = 980 =============== 981 */ 982 983 void Cmd_Fire (void) 984 { 985 buttonheld[bt_attack] = true; 986 987 gamestate.weaponframe = 0; 988 989 player->state = &s_attack; 990 991 gamestate.attackframe = 0; 992 gamestate.attackcount = 993 attackinfo[gamestate.weapon][gamestate.attackframe].tics; 994 gamestate.weaponframe = 995 attackinfo[gamestate.weapon][gamestate.attackframe].frame; 996 } 997 998 //=========================================================================== 999 1000 /* 1001 =============== 1002 = 1003 = Cmd_Use 1004 = 1005 =============== 1006 */ 1007 1008 void Cmd_Use (void) 1009 { 1010 objtype *check; 1011 int checkx,checky,doornum,dir; 1012 boolean elevatorok; 1013 1014 1015 // 1016 // find which cardinal direction the player is facing 1017 // 1018 if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8) 1019 { 1020 checkx = player->tilex + 1; 1021 checky = player->tiley; 1022 dir = di_east; 1023 elevatorok = true; 1024 } 1025 else if (player->angle < 3*ANGLES/8) 1026 { 1027 checkx = player->tilex; 1028 checky = player->tiley-1; 1029 dir = di_north; 1030 elevatorok = false; 1031 } 1032 else if (player->angle < 5*ANGLES/8) 1033 { 1034 checkx = player->tilex - 1; 1035 checky = player->tiley; 1036 dir = di_west; 1037 elevatorok = true; 1038 } 1039 else 1040 { 1041 checkx = player->tilex; 1042 checky = player->tiley + 1; 1043 dir = di_south; 1044 elevatorok = false; 1045 } 1046 1047 doornum = tilemap[checkx][checky]; 1048 if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE) 1049 { 1050 // 1051 // pushable wall 1052 // 1053 1054 PushWall (checkx,checky,dir); 1055 return; 1056 } 1057 if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok) 1058 { 1059 // 1060 // use elevator 1061 // 1062 buttonheld[bt_use] = true; 1063 1064 tilemap[checkx][checky]++; // flip switch 1065 if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE) 1066 playstate = ex_secretlevel; 1067 else 1068 playstate = ex_completed; 1069 SD_PlaySound (LEVELDONESND); 1070 SD_WaitSoundDone(); 1071 } 1072 else if (!buttonheld[bt_use] && doornum & 0x80) 1073 { 1074 buttonheld[bt_use] = true; 1075 OperateDoor (doornum & ~0x80); 1076 } 1077 else 1078 SD_PlaySound (DONOTHINGSND); 1079 1080 } 1081 1082 /* 1083 ============================================================================= 1084 1085 PLAYER CONTROL 1086 1087 ============================================================================= 1088 */ 1089 1090 1091 1092 /* 1093 =============== 1094 = 1095 = SpawnPlayer 1096 = 1097 =============== 1098 */ 1099 1100 void SpawnPlayer (int tilex, int tiley, int dir) 1101 { 1102 player->obclass = playerobj; 1103 player->active = true; 1104 player->tilex = tilex; 1105 player->tiley = tiley; 1106 player->areanumber = 1107 *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex); 1108 player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2; 1109 player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2; 1110 player->state = &s_player; 1111 player->angle = (1-dir)*90; 1112 if (player->angle<0) 1113 player->angle += ANGLES; 1114 player->flags = FL_NEVERMARK; 1115 Thrust (0,0); // set some variables 1116 1117 InitAreas (); 1118 } 1119 1120 1121 //=========================================================================== 1122 1123 /* 1124 =============== 1125 = 1126 = T_KnifeAttack 1127 = 1128 = Update player hands, and try to do damage when the proper frame is reached 1129 = 1130 =============== 1131 */ 1132 1133 void KnifeAttack (objtype *ob) 1134 { 1135 objtype *check,*closest; 1136 long dist; 1137 1138 SD_PlaySound (ATKKNIFESND); 1139 // actually fire 1140 dist = 0x7fffffff; 1141 closest = NULL; 1142 for (check=ob->next ; check ; check=check->next) 1143 if ( (check->flags & FL_SHOOTABLE) 1144 && (check->flags & FL_VISABLE) 1145 && abs (check->viewx-centerx) < shootdelta 1146 ) 1147 { 1148 if (check->transx < dist) 1149 { 1150 dist = check->transx; 1151 closest = check; 1152 } 1153 } 1154 1155 if (!closest || dist> 0x18000l) 1156 { 1157 // missed 1158 1159 return; 1160 } 1161 1162 // hit something 1163 DamageActor (closest,US_RndT() >> 4); 1164 } 1165 1166 1167 1168 void GunAttack (objtype *ob) 1169 { 1170 objtype *check,*closest,*oldclosest; 1171 int damage; 1172 int dx,dy,dist; 1173 long viewdist; 1174 1175 switch (gamestate.weapon) 1176 { 1177 case wp_pistol: 1178 SD_PlaySound (ATKPISTOLSND); 1179 break; 1180 case wp_machinegun: 1181 SD_PlaySound (ATKMACHINEGUNSND); 1182 break; 1183 case wp_chaingun: 1184 SD_PlaySound (ATKGATLINGSND); 1185 break; 1186 } 1187 1188 madenoise = true; 1189 1190 // 1191 // find potential targets 1192 // 1193 viewdist = 0x7fffffffl; 1194 closest = NULL; 1195 1196 while (1) 1197 { 1198 oldclosest = closest; 1199 1200 for (check=ob->next ; check ; check=check->next) 1201 if ( (check->flags & FL_SHOOTABLE) 1202 && (check->flags & FL_VISABLE) 1203 && abs (check->viewx-centerx) < shootdelta 1204 ) 1205 { 1206 if (check->transx < viewdist) 1207 { 1208 viewdist = check->transx; 1209 closest = check; 1210 } 1211 } 1212 1213 if (closest == oldclosest) 1214 return; // no more targets, all missed 1215 1216 // 1217 // trace a line from player to enemey 1218 // 1219 if (CheckLine(closest)) 1220 break; 1221 1222 } 1223 1224 // 1225 // hit something 1226 // 1227 dx = abs(closest->tilex - player->tilex); 1228 dy = abs(closest->tiley - player->tiley); 1229 dist = dx>dy ? dx:dy; 1230 1231 if (dist<2) 1232 damage = US_RndT() / 4; 1233 else if (dist<4) 1234 damage = US_RndT() / 6; 1235 else 1236 { 1237 if ( (US_RndT() / 12) < dist) // missed 1238 return; 1239 damage = US_RndT() / 6; 1240 } 1241 1242 DamageActor (closest,damage); 1243 } 1244 1245 //=========================================================================== 1246 1247 /* 1248 =============== 1249 = 1250 = VictorySpin 1251 = 1252 =============== 1253 */ 1254 1255 void VictorySpin (void) 1256 { 1257 long desty; 1258 1259 if (player->angle > 270) 1260 { 1261 player->angle -= tics * 3; 1262 if (player->angle < 270) 1263 player->angle = 270; 1264 } 1265 else if (player->angle < 270) 1266 { 1267 player->angle += tics * 3; 1268 if (player->angle > 270) 1269 player->angle = 270; 1270 } 1271 1272 desty = (((long)player->tiley-5)<<TILESHIFT)-0x3000; 1273 1274 if (player->y > desty) 1275 { 1276 player->y -= tics*4096; 1277 if (player->y < desty) 1278 player->y = desty; 1279 } 1280 } 1281 1282 1283 //=========================================================================== 1284 1285 /* 1286 =============== 1287 = 1288 = T_Attack 1289 = 1290 =============== 1291 */ 1292 1293 void T_Attack (objtype *ob) 1294 { 1295 struct atkinf *cur; 1296 1297 UpdateFace (); 1298 1299 if (gamestate.victoryflag) // watching the BJ actor 1300 { 1301 VictorySpin (); 1302 return; 1303 } 1304 1305 if ( buttonstate[bt_use] && !buttonheld[bt_use] ) 1306 buttonstate[bt_use] = false; 1307 1308 if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) 1309 buttonstate[bt_attack] = false; 1310 1311 ControlMovement (ob); 1312 if (gamestate.victoryflag) // watching the BJ actor 1313 return; 1314 1315 plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned 1316 pluy = player->y >> UNSIGNEDSHIFT; 1317 player->tilex = player->x >> TILESHIFT; // scale to tile values 1318 player->tiley = player->y >> TILESHIFT; 1319 1320 // 1321 // change frame and fire 1322 // 1323 gamestate.attackcount -= tics; 1324 while (gamestate.attackcount <= 0) 1325 { 1326 cur = &attackinfo[gamestate.weapon][gamestate.attackframe]; 1327 switch (cur->attack) 1328 { 1329 case -1: 1330 ob->state = &s_player; 1331 if (!gamestate.ammo) 1332 { 1333 gamestate.weapon = wp_knife; 1334 DrawWeapon (); 1335 } 1336 else 1337 { 1338 if (gamestate.weapon != gamestate.chosenweapon) 1339 { 1340 gamestate.weapon = gamestate.chosenweapon; 1341 DrawWeapon (); 1342 } 1343 }; 1344 gamestate.attackframe = gamestate.weaponframe = 0; 1345 return; 1346 1347 case 4: 1348 if (!gamestate.ammo) 1349 break; 1350 if (buttonstate[bt_attack]) 1351 gamestate.attackframe -= 2; 1352 case 1: 1353 if (!gamestate.ammo) 1354 { // can only happen with chain gun 1355 gamestate.attackframe++; 1356 break; 1357 } 1358 GunAttack (ob); 1359 gamestate.ammo--; 1360 DrawAmmo (); 1361 break; 1362 1363 case 2: 1364 KnifeAttack (ob); 1365 break; 1366 1367 case 3: 1368 if (gamestate.ammo && buttonstate[bt_attack]) 1369 gamestate.attackframe -= 2; 1370 break; 1371 } 1372 1373 gamestate.attackcount += cur->tics; 1374 gamestate.attackframe++; 1375 gamestate.weaponframe = 1376 attackinfo[gamestate.weapon][gamestate.attackframe].frame; 1377 } 1378 1379 } 1380 1381 1382 1383 //=========================================================================== 1384 1385 /* 1386 =============== 1387 = 1388 = T_Player 1389 = 1390 =============== 1391 */ 1392 1393 void T_Player (objtype *ob) 1394 { 1395 if (gamestate.victoryflag) // watching the BJ actor 1396 { 1397 VictorySpin (); 1398 return; 1399 } 1400 1401 UpdateFace (); 1402 CheckWeaponChange (); 1403 1404 if ( buttonstate[bt_use] ) 1405 Cmd_Use (); 1406 1407 if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) 1408 Cmd_Fire (); 1409 1410 ControlMovement (ob); 1411 if (gamestate.victoryflag) // watching the BJ actor 1412 return; 1413 1414 1415 plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned 1416 pluy = player->y >> UNSIGNEDSHIFT; 1417 player->tilex = player->x >> TILESHIFT; // scale to tile values 1418 player->tiley = player->y >> TILESHIFT; 1419 } 1420 1421