p_pspr.c (29596B)
1 /* P_pspr.c */ 2 3 #include "doomdef.h" 4 #include "p_local.h" 5 6 #define LOWERSPEED FRACUNIT*7 7 #define RAISESPEED FRACUNIT*7 8 9 #define WEAPONX (0)*FRACUNIT 10 #define WEAPONBOTTOM (96)*FRACUNIT //old 128 11 #define WEAPONTOP (0)*FRACUNIT //old 32 12 13 #define RECOILPITCH 0x2AA8000 14 15 #define BFGCELLS 40 /* plasma cells for a bfg attack */ 16 17 #define LASERRANGE (4096*FRACUNIT) 18 #define LASERAIMHEIGHT (40*FRACUNIT) 19 #define LASERDISTANCE (30) 20 21 extern int ArtifactLookupTable[8]; 22 23 /*============================================================================= */ 24 25 int ticremainder[MAXPLAYERS]; // 800A5E70 26 27 /* 28 ================== 29 = 30 = P_SetupPsprites 31 = 32 = Called at start of level for each player 33 ================== 34 */ 35 36 void P_SetupPsprites (int curplayer) // 8001B0D0 37 { 38 int i; 39 player_t *player; 40 41 ticremainder[curplayer] = 0; 42 player = &players[curplayer]; 43 44 /* remove all psprites */ 45 46 for (i=0 ; i<NUMPSPRITES ; i++) 47 { 48 player->psprites[i].state = NULL; 49 player->psprites[i].alpha = 255; 50 } 51 52 /* spawn the gun */ 53 player->pendingweapon = player->readyweapon; 54 P_BringUpWeapon (player); 55 } 56 57 /* 58 ================== 59 = 60 = P_MovePsprites 61 = 62 = Called every tic by player thinking routine 63 ================== 64 */ 65 66 void P_MovePsprites (player_t *player) // 8001B14C 67 { 68 int i; 69 pspdef_t *psp; 70 state_t *state; 71 72 ticremainder[0] += vblsinframe[0]; 73 74 while (ticremainder[0] >= 2) 75 { 76 ticremainder[0] -= 2; 77 78 psp = &player->psprites[0]; 79 for (i=0 ; i<NUMPSPRITES ; i++, psp++) 80 { 81 if ( (state = psp->state) != 0) /* a null state means not active */ 82 { 83 /* drop tic count and possibly change state */ 84 if (psp->tics != -1) /* a -1 tic count never changes */ 85 { 86 psp->tics--; 87 if (!psp->tics) 88 P_SetPsprite (player, i, psp->state->nextstate); 89 } 90 } 91 } 92 } 93 94 player->psprites[ps_flash].sx = player->psprites[ps_flashalpha].sx = player->psprites[ps_weapon].sx; 95 player->psprites[ps_flash].sy = player->psprites[ps_flashalpha].sy = player->psprites[ps_weapon].sy; 96 } 97 98 /*============================================================================= */ 99 100 /* 101 ================= 102 = 103 = P_RecursiveSound 104 = 105 = If a monster yells at a player, it will alert other monsters to the player 106 = 107 ================= 108 */ 109 110 mobj_t *soundtarget; // 800A5E74 111 112 void P_RecursiveSound (sector_t *sec, int soundblocks) // 8001B254 113 { 114 int i; 115 line_t *check; 116 sector_t *other; 117 sector_t *front, *back; 118 119 /* wake up all monsters in this sector */ 120 if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) 121 return; /* already flooded */ 122 123 sec->validcount = validcount; 124 sec->soundtraversed = soundblocks+1; 125 sec->soundtarget = soundtarget; 126 127 for (i=0 ;i<sec->linecount ; i++) 128 { 129 check = sec->lines[i]; 130 back = check->backsector; 131 if (!back) 132 continue; /* single sided */ 133 134 front = check->frontsector; 135 if (front->floorheight >= back->ceilingheight || 136 front->ceilingheight <= back->floorheight || 137 back->floorheight == back->ceilingheight) // [d64] added this check 138 continue; /* closed door */ 139 140 if ( front == sec) 141 other = back; 142 else 143 other = front; 144 145 if (check->flags & ML_SOUNDBLOCK) 146 { 147 if (!soundblocks) 148 P_RecursiveSound (other, 1); 149 } 150 else 151 P_RecursiveSound (other, soundblocks); 152 } 153 } 154 155 156 /* 157 ================= 158 = 159 = P_NoiseAlert 160 = 161 ================= 162 */ 163 164 void P_NoiseAlert (player_t *player) // 8001B3A4 165 { 166 sector_t *sec; 167 168 sec = player->mo->subsector->sector; 169 170 if (player->lastsoundsector == (void *)sec) 171 return; /* don't bother doing it again here */ 172 173 soundtarget = player->mo; 174 player->lastsoundsector = (void *)sec; 175 176 validcount++; 177 P_RecursiveSound (sec, 0); 178 } 179 180 181 /* 182 ================== 183 = 184 = P_SetPsprite 185 = 186 ================== 187 */ 188 189 void P_SetPsprite (player_t *player, int position, statenum_t stnum) // 8001B3FC 190 { 191 pspdef_t *psp; 192 state_t *state; 193 194 psp = &player->psprites[position]; 195 196 do 197 { 198 if (!stnum) 199 { 200 psp->state = NULL; 201 break; /* object removed itself */ 202 } 203 state = &states[stnum]; 204 psp->state = state; 205 psp->tics = state->tics; /* could be 0 */ 206 207 /* call action routine */ 208 if (state->action) 209 { 210 state->action (player, psp); 211 if (!psp->state) 212 break; 213 } 214 stnum = psp->state->nextstate; 215 } while (!psp->tics); /* an initial state of 0 could cycle through */ 216 } 217 218 219 /* 220 =============================================================================== 221 222 PSPRITE ACTIONS 223 224 =============================================================================== 225 */ 226 227 /* 228 =============================================================================== 229 230 PSPRITE ACTIONS 231 232 =============================================================================== 233 */ 234 235 weaponinfo_t weaponinfo[NUMWEAPONS] = // 8005AD80 236 { 237 { /* saw */ 238 /* ammo */ am_noammo, 239 /* upstate */ S_708,//S_SAWUP, 240 /* downstate */ S_707,//S_SAWDOWN, 241 /* readystate */ S_705,//S_SAW, 242 /* atkstate */ S_709,//S_SAW1, 243 /* flashstate */ S_000 //S_NULL 244 }, 245 246 { /* fist */ 247 /* ammo */ am_noammo, 248 /* upstate */ S_714,//S_PUNCHUP, 249 /* downstate */ S_713,//S_PUNCHDOWN, 250 /* readystate */ S_712,//S_PUNCH, 251 /* atkstate */ S_715,//S_PUNCH1, 252 /* flashstate */ S_000 //S_NULL 253 }, 254 255 { /* pistol */ 256 /* ammo */ am_clip, 257 /* upstate */ S_722,//S_PISTOLUP, 258 /* downstate */ S_721,//S_PISTOLDOWN, 259 /* readystate */ S_720,//S_PISTOL, 260 /* atkstate */ S_724,//S_PISTOL2, 261 /* flashstate */ S_728 //S_PISTOLFLASH 262 }, 263 264 { /* shotgun */ 265 /* ammo */ am_shell, 266 /* upstate */ S_731,//S_SGUNUP, 267 /* downstate */ S_730,//S_SGUNDOWN, 268 /* readystate */ S_729,//S_SGUN, 269 /* atkstate */ S_733,//S_SGUN2, 270 /* flashstate */ S_738 //S_SGUNFLASH1 271 }, 272 273 { /* super shotgun */ 274 /* ammo */ am_shell, 275 /* upstate */ S_741,//S_DSGUNUP, 276 /* downstate */ S_740,//S_DSGUNDOWN, 277 /* readystate */ S_739,//S_DSGUN, 278 /* atkstate */ S_742,//S_DSGUN1, 279 /* flashstate */ S_752 //S_DSGUNFLASH1 280 }, 281 282 { /* chaingun */ 283 /* ammo */ am_clip, 284 /* upstate */ S_755,//S_CHAINUP, 285 /* downstate */ S_754,//S_CHAINDOWN, 286 /* readystate */ S_753,//S_CHAIN, 287 /* atkstate */ S_756,//S_CHAIN1, 288 /* flashstate */ S_759 //S_CHAINFLASH1 289 }, 290 291 { /* missile */ 292 /* ammo */ am_misl, 293 /* upstate */ S_763,//S_MISSILEUP, 294 /* downstate */ S_762,//S_MISSILEDOWN, 295 /* readystate */ S_761,//S_MISSILE, 296 /* atkstate */ S_764,//S_MISSILE1, 297 /* flashstate */ S_767 //S_MISSILEFLASH1 298 }, 299 300 { /* plasma */ 301 /* ammo */ am_cell, 302 /* upstate */ S_773,//S_PLASMAUP, 303 /* downstate */ S_772,//S_PLASMADOWN, 304 /* readystate */ S_771,//S_PLASMA, 305 /* atkstate */ S_775,//S_PLASMA1, 306 /* flashstate */ S_000 //S_NULL 307 }, 308 309 { /* bfg */ 310 /* ammo */ am_cell, 311 /* upstate */ S_783,//S_BFGUP, 312 /* downstate */ S_782,//S_BFGDOWN, 313 /* readystate */ S_781,//S_BFG, 314 /* atkstate */ S_784,//S_BFG1, 315 /* flashstate */ S_788 //S_BFGFLASH1 316 }, 317 318 { /* laser rifle */ 319 /* ammo */ am_cell, 320 /* upstate */ S_793,//S_LASERUP, 321 /* downstate */ S_792,//S_LASERDOWN, 322 /* readystate */ S_791,//S_LASER, 323 /* atkstate */ S_794,//S_LASER1, 324 /* flashstate */ S_796 //S_LASERFLASH 325 } 326 }; 327 328 329 /* 330 ================ 331 = 332 = P_BringUpWeapon 333 = 334 = Starts bringing the pending weapon up from the bottom of the screen 335 = Uses player 336 ================ 337 */ 338 339 void P_BringUpWeapon (player_t *player) // 8001B4BC 340 { 341 statenum_t new; 342 343 if (player->pendingweapon == wp_nochange) 344 player->pendingweapon = player->readyweapon; 345 346 if (player->pendingweapon == wp_chainsaw) 347 S_StartSound(player->mo, sfx_sawup); 348 else if (player->pendingweapon == wp_plasma) 349 S_StartSound(player->mo, sfx_electric); 350 351 new = weaponinfo[player->pendingweapon].upstate; 352 353 player->pendingweapon = wp_nochange; 354 player->psprites[ps_weapon].sx = WEAPONX; 355 player->psprites[ps_weapon].sy = WEAPONBOTTOM; 356 player->psprites[ps_flashalpha].alpha = 255; 357 P_SetPsprite (player, ps_weapon, new); 358 } 359 360 /* 361 ================ 362 = 363 = P_DropWeapon 364 = 365 = Player died, so put the weapon away 366 ================ 367 */ 368 369 void P_DropWeapon (player_t *player) // 8001B580 370 { 371 P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate); 372 } 373 374 /* 375 ================ 376 = 377 = P_CheckAmmo 378 = 379 = returns true if there is enough ammo to shoot 380 = if not, selects the next weapon to use 381 ================ 382 */ 383 384 boolean P_CheckAmmo (player_t *player) // 8001B5BC 385 { 386 ammotype_t ammo; 387 int count; 388 389 ammo = weaponinfo[player->readyweapon].ammo; 390 391 if (player->readyweapon == wp_bfg) 392 count = BFGCELLS; 393 else if (player->readyweapon == wp_laser) 394 { 395 count = ArtifactLookupTable[player->artifacts]; 396 if (count == 0) 397 count = 1; 398 } 399 else if (player->readyweapon == wp_supershotgun) 400 count = 2; // Double barrel. 401 else 402 count = 1; 403 404 if (ammo == am_noammo || player->ammo[ammo] >= count) 405 return true; 406 407 /* out of ammo, pick a weapon to change to */ 408 do 409 { 410 if (player->weaponowned[wp_plasma] && player->ammo[am_cell]) 411 player->pendingweapon = wp_plasma; 412 else if (player->weaponowned[wp_supershotgun] && player->ammo[am_shell] > 2) 413 player->pendingweapon = wp_supershotgun; 414 else if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) 415 player->pendingweapon = wp_chaingun; 416 else if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) 417 player->pendingweapon = wp_shotgun; 418 else if (player->ammo[am_clip]) 419 player->pendingweapon = wp_pistol; 420 else if (player->weaponowned[wp_chainsaw]) 421 player->pendingweapon = wp_chainsaw; 422 else if (player->weaponowned[wp_missile] && player->ammo[am_misl]) 423 player->pendingweapon = wp_missile; 424 else if (player->weaponowned[wp_bfg] && player->ammo[am_cell]>40) 425 player->pendingweapon = wp_bfg; 426 else 427 player->pendingweapon = wp_fist; 428 } while (player->pendingweapon == wp_nochange); 429 430 P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate); 431 432 return false; 433 } 434 435 436 /* 437 ================ 438 = 439 = P_FireWeapon 440 = 441 ================ 442 */ 443 444 void P_FireWeapon (player_t *player) // 8001B7CC 445 { 446 statenum_t new; 447 448 if (!P_CheckAmmo (player)) 449 return; 450 451 P_SetMobjState (player->mo, S_006/*S_PLAY_ATK1*/); 452 453 player->psprites[ps_weapon].sx = WEAPONX; 454 player->psprites[ps_weapon].sy = WEAPONTOP; 455 new = weaponinfo[player->readyweapon].atkstate; 456 P_SetPsprite (player, ps_weapon, new); 457 P_NoiseAlert (player); 458 } 459 460 /* 461 ================= 462 = 463 = A_WeaponReady 464 = 465 = The player can fire the weapon or change to another weapon at this time 466 = 467 ================= 468 */ 469 470 void A_WeaponReady (player_t *player, pspdef_t *psp) // 8001B83C 471 { 472 statenum_t new; 473 int angle; 474 475 /* */ 476 /* check for change */ 477 /* if player is dead, put the weapon away */ 478 /* */ 479 if (player->pendingweapon != wp_nochange || !player->health) 480 { 481 /* change weapon (pending weapon should allready be validated) */ 482 P_DropWeapon(player); 483 return; 484 } 485 486 /* */ 487 /* check for fire */ 488 /* */ 489 /* the missile launcher and bfg do not auto fire */ 490 if (ticbuttons[0] & BT_DATA[0]->BT_ATTACK) 491 { 492 P_FireWeapon (player); 493 return; 494 } 495 496 /* */ 497 /* bob the weapon based on movement speed */ 498 /* */ 499 //angle = (64*gamevbls)&(FINEANGLES-1); 500 angle = (64*ticon)&(FINEANGLES-1); // PsxDoom/D64 use ticon no gamevbls 501 psp->sx = WEAPONX + FixedMul(player->bob, finecosine[angle]); 502 angle &= FINEANGLES/2-1; 503 psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); 504 } 505 506 507 /* 508 ================= 509 = 510 = A_ReFire 511 = 512 = The player can re fire the weapon without lowering it entirely 513 = 514 ================= 515 */ 516 517 void A_ReFire (player_t *player, pspdef_t *psp) // 8001B91C 518 { 519 /* */ 520 /* check for fire (if a weaponchange is pending, let it go through instead) */ 521 /* */ 522 if ((ticbuttons[0] & BT_DATA[0]->BT_ATTACK) 523 && player->pendingweapon == wp_nochange && player->health) 524 { 525 player->refire++; 526 P_FireWeapon (player); 527 } 528 else 529 { 530 player->refire = 0; 531 P_CheckAmmo (player); 532 } 533 } 534 535 /* 536 ================= 537 = 538 = A_CheckReload 539 = 540 ================= 541 */ 542 543 void A_CheckReload(player_t *player, pspdef_t *psp) // 8001B9A0 544 { 545 P_CheckAmmo(player); 546 } 547 548 /* 549 ================= 550 = 551 = A_Lower 552 = 553 ================= 554 */ 555 556 void A_Lower (player_t *player, pspdef_t *psp) // 8001B9C0 557 { 558 psp->sy += LOWERSPEED; 559 if (psp->sy < WEAPONBOTTOM ) 560 return; 561 562 /* */ 563 /* [d64] stop plasma buzz */ 564 /* */ 565 if (player->readyweapon == wp_plasma) 566 S_StopSound(NULL, sfx_electric); 567 568 /* */ 569 /* [d64] clear flash graphic drawer */ 570 /* */ 571 P_SetPsprite(player, ps_flash, S_000); 572 573 if (player->playerstate == PST_DEAD) 574 { 575 psp->sy = WEAPONBOTTOM; 576 return; /* don't bring weapon back up */ 577 } 578 579 /* */ 580 /* The old weapon has been lowered off the screen, so change the weapon */ 581 /* and start raising it */ 582 /* */ 583 if (!player->health) 584 { /* player is dead, so keep the weapon off screen */ 585 P_SetPsprite (player, ps_weapon, S_000); 586 return; 587 } 588 589 player->readyweapon = player->pendingweapon; 590 591 P_BringUpWeapon (player); 592 } 593 594 595 /* 596 ================= 597 = 598 = A_Raise 599 = 600 ================= 601 */ 602 603 void A_Raise (player_t *player, pspdef_t *psp) // 8001BA84 604 { 605 statenum_t new; 606 607 psp->sy -= RAISESPEED; 608 609 if (psp->sy > WEAPONTOP ) 610 return; 611 612 psp->sy = WEAPONTOP; 613 614 /* */ 615 /* the weapon has been raised all the way, so change to the ready state */ 616 /* */ 617 new = weaponinfo[player->readyweapon].readystate; 618 619 P_SetPsprite (player, ps_weapon, new); 620 } 621 622 623 /* 624 ================ 625 = 626 = A_GunFlash 627 = 628 ================= 629 */ 630 631 void A_GunFlash (player_t *player, pspdef_t *psp) // 8001BAD8 632 { 633 /* [d64] set alpha on flash frame */ 634 if(player->readyweapon == wp_missile) 635 player->psprites[ps_flashalpha].alpha = 100; 636 637 P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate); 638 } 639 640 641 /* 642 =============================================================================== 643 644 WEAPON ATTACKS 645 646 =============================================================================== 647 */ 648 649 650 /* 651 ================== 652 = 653 = A_Punch 654 = 655 ================== 656 */ 657 658 void A_Punch (player_t *player, pspdef_t *psp) // 8001BB2C 659 { 660 angle_t angle; 661 int damage; 662 663 //damage = ((P_Random ()&7)*3)+3; 664 damage = ((P_Random()&7)+1)*3; 665 if (player->powers[pw_strength]) 666 damage *= 10; 667 angle = player->mo->angle; 668 angle += (angle_t)(P_Random()-P_Random())<<18; 669 P_LineAttack (player->mo, angle, 0, MELEERANGE, MAXINT, damage); 670 /* turn to face target */ 671 if (linetarget) 672 { 673 S_StartSound(player->mo, sfx_punch); 674 player->mo->angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y); 675 } 676 } 677 678 /* 679 ================== 680 = 681 = A_Saw 682 = 683 ================== 684 */ 685 686 void A_Saw (player_t *player, pspdef_t *psp) // 8001BC1C 687 { 688 angle_t angle; 689 int damage; 690 int rnd1, rnd2; 691 692 //damage = ((P_Random ()&7)*3)+3; 693 damage = ((P_Random()&7)+1)*3; 694 angle = player->mo->angle; 695 rnd1 = P_Random(); 696 rnd2 = P_Random(); 697 angle += (angle_t)(rnd2-rnd1)<<18; 698 /* use meleerange + 1 se the puff doesn't skip the flash */ 699 P_LineAttack (player->mo, angle, 0, MELEERANGE+1, MAXINT, damage); 700 if (!linetarget) 701 { 702 S_StartSound (player->mo, sfx_saw1); 703 return; 704 } 705 S_StartSound (player->mo, sfx_saw2); 706 707 /* turn to face target */ 708 angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y); 709 if (angle - player->mo->angle > ANG180) 710 { 711 if (angle - player->mo->angle < -ANG90/20) 712 player->mo->angle = angle + ANG90/21; 713 else 714 player->mo->angle -= ANG90/20; 715 } 716 else 717 { 718 if (angle - player->mo->angle > ANG90/20) 719 player->mo->angle = angle - ANG90/21; 720 else 721 player->mo->angle += ANG90/20; 722 } 723 player->mo->flags |= MF_JUSTATTACKED; 724 } 725 726 /* 727 ================== 728 = 729 = A_ChainSawReady 730 = 731 ================== 732 */ 733 734 void A_ChainSawReady(player_t *player, pspdef_t *psp) // 8001BDA8 735 { 736 S_StartSound(player->mo, sfx_sawidle); 737 A_WeaponReady(player, psp); 738 } 739 740 /* 741 ================== 742 = 743 = A_FireMissile 744 = 745 ================== 746 */ 747 748 void A_FireMissile (player_t *player, pspdef_t *psp) // 8001BDE4 749 { 750 player->ammo[weaponinfo[player->readyweapon].ammo]--; 751 752 player->recoilpitch = RECOILPITCH; 753 754 if(player->onground) 755 P_Thrust(player, player->mo->angle + ANG180, FRACUNIT); 756 757 P_SpawnPlayerMissile (player->mo, MT_PROJ_ROCKET); 758 } 759 760 761 /* 762 ================== 763 = 764 = A_FireBFG 765 = 766 ================== 767 */ 768 769 void A_FireBFG (player_t *player, pspdef_t *psp) // 8001BE78 770 { 771 player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; 772 P_SpawnPlayerMissile (player->mo, MT_PROJ_BFG); 773 } 774 775 776 /* 777 ================== 778 = 779 = A_PlasmaAnimate 780 = 781 ================== 782 */ 783 int pls_animpic = 0; // 8005AE70 784 785 void A_PlasmaAnimate(player_t *player, pspdef_t *psp) // 8001BED8 786 { 787 P_SetPsprite(player, ps_flash, pls_animpic + S_778); 788 789 if (++pls_animpic >= 3) 790 pls_animpic = 0; 791 } 792 793 /* 794 ================== 795 = 796 = A_FirePlasma 797 = 798 ================== 799 */ 800 801 void A_FirePlasma (player_t *player, pspdef_t *psp) // 8001BF2C 802 { 803 player->ammo[weaponinfo[player->readyweapon].ammo]--; 804 P_SetPsprite (player,ps_flash,S_000); 805 P_SpawnPlayerMissile (player->mo, MT_PROJ_PLASMA); 806 } 807 808 /* 809 =============== 810 = 811 = P_BulletSlope 812 = 813 =============== 814 */ 815 816 fixed_t bulletslope; // 800A5E78 817 818 void P_BulletSlope(mobj_t* mo) // 8001BF88 819 { 820 angle_t an; 821 822 // see which target is to be aimed at 823 an = mo->angle; 824 bulletslope = P_AimLineAttack(mo, an, 0, 16 * 64 * FRACUNIT); 825 826 if (!linetarget) 827 { 828 an += 1 << 26; 829 bulletslope = P_AimLineAttack(mo, an, 0, 16 * 64 * FRACUNIT); 830 if (!linetarget) 831 { 832 an -= 2 << 26; 833 bulletslope = P_AimLineAttack(mo, an, 0, 16 * 64 * FRACUNIT); 834 } 835 } 836 } 837 838 /* 839 =============== 840 = 841 = P_GunShot 842 = 843 =============== 844 */ 845 846 void P_GunShot (mobj_t *mo, boolean accurate) // 8001C024 847 { 848 angle_t angle; 849 int damage; 850 int rnd1, rnd2; 851 852 damage = ((P_Random ()&3)*4)+4; 853 angle = mo->angle; 854 if (!accurate) 855 { 856 rnd1 = P_Random(); 857 rnd2 = P_Random(); 858 angle += (rnd2-rnd1)<<18; 859 } 860 P_LineAttack (mo, angle, 0, MISSILERANGE, bulletslope, damage); 861 } 862 863 /* 864 ================== 865 = 866 = A_FirePistol 867 = 868 ================== 869 */ 870 871 void A_FirePistol (player_t *player, pspdef_t *psp) // 8001C0B4 872 { 873 S_StartSound (player->mo, sfx_pistol); 874 875 player->ammo[weaponinfo[player->readyweapon].ammo]--; 876 P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate); 877 P_BulletSlope(player->mo); 878 879 P_GunShot (player->mo, !player->refire); 880 } 881 882 /* 883 ================== 884 = 885 = A_FireShotgun 886 = 887 ================== 888 */ 889 890 void A_FireShotgun (player_t *player, pspdef_t *psp) // 8001C138 891 { 892 angle_t angle; 893 int damage; 894 int i; 895 896 S_StartSound (player->mo, sfx_shotgun); 897 898 player->ammo[weaponinfo[player->readyweapon].ammo]--; 899 player->recoilpitch = RECOILPITCH; 900 901 P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate); 902 P_BulletSlope(player->mo); 903 904 for (i=0 ; i<7 ; i++) 905 { 906 P_GunShot(player->mo, false); 907 } 908 } 909 910 /* 911 ================== 912 = 913 = A_FireShotgun2 914 = 915 ================== 916 */ 917 918 void A_FireShotgun2(player_t *player, pspdef_t *psp) // 8001C210 919 { 920 angle_t angle; 921 int damage; 922 int i; 923 924 S_StartSound(player->mo, sfx_sht2fire); 925 P_SetMobjState(player->mo, S_007); 926 927 player->ammo[weaponinfo[player->readyweapon].ammo] -= 2; 928 player->recoilpitch = RECOILPITCH; 929 930 if(player->onground) 931 P_Thrust(player, player->mo->angle + ANG180, FRACUNIT); 932 933 P_SetPsprite(player, ps_flashalpha, weaponinfo[player->readyweapon].flashstate); 934 P_BulletSlope(player->mo); 935 936 for (i = 0; i<20; i++) 937 { 938 //damage = ((P_Random() % 3) * 5) + 5; 939 damage = 5 * (P_Random() % 3 + 1); 940 angle = player->mo->angle; 941 angle += (P_Random() - P_Random()) << 19; 942 P_LineAttack(player->mo, angle, 0, MISSILERANGE, bulletslope + ((P_Random() - P_Random()) << 5), damage); 943 } 944 } 945 946 /* 947 ================== 948 = 949 = A_CockSgun 950 = 951 ================== 952 */ 953 #if 0 //No Used In PSX Doom/ Doom64 954 void A_CockSgun (player_t *player, pspdef_t *psp) 955 { 956 S_StartSound (player->mo, sfx_sgcock); 957 } 958 #endif // 0 959 960 /* 961 ================== 962 = 963 = A_FireCGun 964 = 965 ================== 966 */ 967 968 void A_FireCGun (player_t *player, pspdef_t *psp) // 8001C3F8 969 { 970 int ammo; 971 int rand; 972 973 ammo = player->ammo[weaponinfo[player->readyweapon].ammo]; 974 975 if (!ammo) 976 return; 977 978 S_StartSound (player->mo, sfx_pistol); 979 980 player->ammo[weaponinfo[player->readyweapon].ammo]--; 981 982 /* randomize sx */ 983 rand = (((P_Random() & 1) << 1) - 1); 984 psp->sx = (rand * FRACUNIT); 985 986 /* randomize sy */ 987 rand = ((((ammo - 1) & 1) << 1) - 1); 988 psp->sy = WEAPONTOP - (rand * (2*FRACUNIT)); 989 990 player->recoilpitch = RECOILPITCH; 991 992 P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate + psp->state - &states[S_756/*S_CHAIN1*/]); 993 P_BulletSlope(player->mo); 994 995 player->psprites[ps_flashalpha].alpha = 160; 996 997 P_GunShot (player->mo, !player->refire); 998 } 999 1000 /* 1001 ================ 1002 = 1003 = A_BFGFlash 1004 = 1005 ================= 1006 */ 1007 1008 void A_BFGFlash(mobj_t* actor) // 8001C548 1009 { 1010 players[0].bfgcount = 100; 1011 actor->alpha = 170; 1012 } 1013 1014 /* 1015 ================ 1016 = 1017 = A_BFGSpray 1018 = 1019 = Spawn a BFG explosion on every monster in view 1020 = 1021 ================= 1022 */ 1023 1024 void A_BFGSpray (mobj_t *mo) // 8001C560 1025 { 1026 int i, j, damage; 1027 angle_t an; 1028 int alpha; 1029 1030 alpha = 0; 1031 1032 /* offset angles from its attack angle */ 1033 for (i=0 ; i<40 ; i++) 1034 { 1035 an = mo->angle - ANG90/2 + ANG90/40*i; 1036 /* mo->target is the originator (player) of the missile */ 1037 P_AimLineAttack (mo->target, an, 0, 16*64*FRACUNIT); 1038 if (!linetarget) 1039 continue; 1040 P_SpawnMobj (linetarget->x, linetarget->y, linetarget->z + (linetarget->height>>1), MT_BFGSPREAD); 1041 damage = 0; 1042 for (j=0;j<15;j++) 1043 { 1044 damage += (P_Random()&7) + 1; 1045 } 1046 P_DamageMobj (linetarget, mo->target,mo->target, damage); 1047 } 1048 1049 alpha = mo->alpha * 3; 1050 if (alpha < 0) 1051 alpha += 3; 1052 1053 mo->alpha = alpha >> 2; 1054 } 1055 1056 /* 1057 ================ 1058 = 1059 = A_BFGsound 1060 = 1061 ================= 1062 */ 1063 1064 void A_BFGsound (player_t *player, pspdef_t *psp) // 8001C698 1065 { 1066 S_StartSound (player->mo, sfx_bfg); 1067 } 1068 1069 #if 0 1070 /* 1071 ================ 1072 = 1073 = A_OpenShotgun2 1074 = 1075 ================= 1076 */ 1077 1078 void A_OpenShotgun2(player_t *player, pspdef_t *psp)//L80021AFC() 1079 { 1080 S_StartSound(player->mo, sfx_dbopn); 1081 } 1082 #endif // 0 1083 1084 /* 1085 ================ 1086 = 1087 = A_LoadShotgun2 1088 = 1089 ================= 1090 */ 1091 1092 void A_LoadShotgun2(player_t *player, pspdef_t *psp) // 8001C6C0 1093 { 1094 S_StartSound(player->mo, sfx_sht2load1); 1095 } 1096 1097 /* 1098 ================ 1099 = 1100 = A_CloseShotgun2 1101 = 1102 ================= 1103 */ 1104 1105 void A_CloseShotgun2(player_t *player, pspdef_t *psp) // 8001C6E8 1106 { 1107 S_StartSound(player->mo, sfx_sht2load2); 1108 //A_ReFire(player, psp); 1109 } 1110 1111 /* 1112 ================ 1113 = 1114 = P_LaserCrossBSP 1115 = 1116 ================= 1117 */ 1118 1119 void P_LaserCrossBSP(int bspnum, laserdata_t *laser) // 8001C710 1120 { 1121 node_t* node; 1122 int ds1, ds2; 1123 int s1, s2; 1124 int dist; 1125 int frac; 1126 mobj_t *marker; 1127 laserdata_t *childlaser; 1128 laser_t *next_cl, *next_l; 1129 fixed_t x, y, z; 1130 fixed_t x1, y1, z1; 1131 fixed_t x2, y2, z2; 1132 fixed_t nx, ny, ndx, ndy; 1133 1134 while(!(bspnum & NF_SUBSECTOR)) 1135 { 1136 node = &nodes[bspnum]; 1137 1138 x1 = laser->x1; 1139 y1 = laser->y1; 1140 z1 = laser->z1; 1141 x2 = laser->x2; 1142 y2 = laser->y2; 1143 z2 = laser->z2; 1144 1145 nx = node->line.x; 1146 ny = node->line.y; 1147 ndx = (node->line.dx >> FRACBITS); 1148 ndy = (node->line.dy >> FRACBITS); 1149 1150 /* traverse nodes */ 1151 ds1 = (((x1 - nx) >> FRACBITS) * ndy) - (((y1 - ny) >> FRACBITS) * ndx); 1152 ds2 = (((x2 - nx) >> FRACBITS) * ndy) - (((y2 - ny) >> FRACBITS) * ndx); 1153 1154 s1 = (ds1 < 0); 1155 s2 = (ds2 < 0); 1156 1157 /* did the two laser points cross the node? */ 1158 if(s1 == s2) 1159 { 1160 bspnum = node->children[s1]; 1161 continue; 1162 } 1163 1164 /* new child laser */ 1165 childlaser = (laserdata_t *)Z_Malloc( sizeof(*childlaser), PU_LEVSPEC, 0); 1166 1167 /* copy laser pointer */ 1168 *childlaser = *laser; 1169 1170 /* get the intercepting point of the laser and node */ 1171 frac = FixedDiv(ds1, ds1 - ds2); 1172 1173 x = (((x2 - x1) >> FRACBITS) * frac) + x1; 1174 y = (((y2 - y1) >> FRACBITS) * frac) + y1; 1175 z = (((z2 - z1) >> FRACBITS) * frac) + z1; 1176 1177 /* update endpoint of current laser to intercept point */ 1178 laser->x2 = x; 1179 laser->y2 = y; 1180 laser->z2 = z; 1181 1182 /* childlaser begins at intercept point */ 1183 childlaser->x1 = x; 1184 childlaser->y1 = y; 1185 childlaser->z1 = z; 1186 1187 /* update distmax */ 1188 dist = (laser->distmax * frac) >> FRACBITS; 1189 1190 childlaser->distmax = laser->distmax - dist; 1191 laser->distmax = dist; 1192 1193 /* point to child laser */ 1194 laser->next = childlaser; 1195 1196 /* traverse child nodes */ 1197 P_LaserCrossBSP(node->children[s1], laser); 1198 1199 laser = childlaser; 1200 bspnum = node->children[s2]; 1201 } 1202 1203 /* subsector was hit, spawn a marker between the two laser points */ 1204 x = (laser->x1 + laser->x2) >> 1; 1205 y = (laser->y1 + laser->y2) >> 1; 1206 z = (laser->z1 + laser->z2) >> 1; 1207 1208 marker = P_SpawnMobj(x, y, z, MT_LASERMARKER); 1209 1210 /* have marker point to which laser it belongs to */ 1211 marker->extradata = (laser_t*)laser; 1212 laser->marker = marker; 1213 } 1214 1215 /* 1216 ================ 1217 = 1218 = T_LaserThinker 1219 = 1220 ================= 1221 */ 1222 1223 void T_LaserThinker(laser_t *laser) // 8001C9B8 1224 { 1225 fade_t *fade; 1226 laserdata_t *pThisLaser; 1227 1228 pThisLaser = laser->laserdata; 1229 pThisLaser ->dist += 64; 1230 1231 /* laser reached its destination? */ 1232 if(pThisLaser->dist >= pThisLaser->distmax) 1233 { 1234 /* reached the end? */ 1235 if (!pThisLaser->next) 1236 { 1237 P_RemoveThinker(&laser->thinker); 1238 1239 /* fade out the laser puff */ 1240 fade = Z_Malloc (sizeof(*fade), PU_LEVSPEC, 0); 1241 P_AddThinker (&fade->thinker); 1242 fade->thinker.function = T_FadeThinker; 1243 fade->amount = -24; 1244 fade->destAlpha = 0; 1245 fade->flagReserve = 0; 1246 fade->mobj = laser->marker; 1247 } 1248 else 1249 { 1250 laser->laserdata = pThisLaser->next; 1251 } 1252 1253 P_RemoveMobj(pThisLaser->marker); 1254 Z_Free(pThisLaser); 1255 } 1256 else 1257 { 1258 /* update laser's location */ 1259 pThisLaser->x1 += (pThisLaser->slopex * 32); 1260 pThisLaser->y1 += (pThisLaser->slopey * 32); 1261 pThisLaser->z1 += (pThisLaser->slopez * 32); 1262 } 1263 } 1264 1265 /* 1266 ================ 1267 = 1268 = A_FireLaser 1269 = 1270 ================= 1271 */ 1272 extern fixed_t aimfrac; // 800A5720 1273 1274 void A_FireLaser(player_t *player, pspdef_t *psp) // 8001CAC0 1275 { 1276 angle_t angleoffs; 1277 angle_t spread; 1278 mobj_t *mobj; 1279 int lasercount; 1280 int i; 1281 fixed_t slopex, slopey, slopez; 1282 fixed_t x, y, z; 1283 fixed_t x1, y1, z1; 1284 fixed_t x2, y2, z2; 1285 byte type; 1286 laserdata_t *laser_data; 1287 laser_t *laser; 1288 fixed_t laserfrac; 1289 int damage; 1290 1291 mobj = player->mo; 1292 1293 type = ArtifactLookupTable[player->artifacts]; 1294 1295 /* setup laser type */ 1296 switch(type) 1297 { 1298 case 1: /* Rapid fire / single shot */ 1299 psp->tics = 5; 1300 lasercount = 1; 1301 angleoffs = mobj->angle; 1302 break; 1303 case 2: /* Rapid fire / double shot */ 1304 psp->tics = 4; 1305 lasercount = 2; 1306 spread = 0x16C0000; 1307 angleoffs = mobj->angle + 0xFF4A0000; 1308 break; 1309 case 3: /* Spread shot */ 1310 psp->tics = 4; 1311 lasercount = 3; 1312 spread = 0x2220000 + (0x2220000 * (player->refire & 3)); 1313 angleoffs = mobj->angle - spread; 1314 break; 1315 default: /* Normal shot */ 1316 lasercount = 1; 1317 angleoffs = mobj->angle; 1318 break; 1319 } 1320 1321 x1 = mobj->x + (finecosine[mobj->angle >> ANGLETOFINESHIFT] * LASERDISTANCE); 1322 y1 = mobj->y + (finesine[mobj->angle >> ANGLETOFINESHIFT] * LASERDISTANCE); 1323 z1 = mobj->z + LASERAIMHEIGHT; 1324 1325 /* setup laser beams */ 1326 for(i = 0; i < lasercount; i++) 1327 { 1328 slopez = P_AimLineAttack(mobj, angleoffs, LASERAIMHEIGHT, LASERRANGE); 1329 1330 if(aimfrac) 1331 laserfrac = (aimfrac << (FRACBITS - 4)) - (4 << FRACBITS); 1332 else 1333 laserfrac = (2048*FRACUNIT); 1334 1335 slopex = finecosine[angleoffs >> ANGLETOFINESHIFT]; 1336 slopey = finesine[angleoffs >> ANGLETOFINESHIFT]; 1337 1338 x2 = mobj->x + FixedMul(slopex, laserfrac); 1339 y2 = mobj->y + FixedMul(slopey, laserfrac); 1340 z2 = z1 + FixedMul(slopez, laserfrac); 1341 1342 z = (z2 - z1) >> FRACBITS; 1343 x = (x2 - x1) >> FRACBITS; 1344 y = (y2 - y1) >> FRACBITS; 1345 1346 /* setup laser */ 1347 laser_data = (laserdata_t *)Z_Malloc( sizeof(*laser_data), PU_LEVSPEC, 0); 1348 1349 /* setup laser head point */ 1350 laser_data->x1 = x1; 1351 laser_data->y1 = y1; 1352 laser_data->z1 = z1; 1353 1354 /* setup laser tail point */ 1355 laser_data->x2 = x2; 1356 laser_data->y2 = y2; 1357 laser_data->z2 = z2; 1358 1359 /* setup movement slope */ 1360 laser_data->slopex = slopex; 1361 laser_data->slopey = slopey; 1362 laser_data->slopez = slopez; 1363 1364 /* setup distance info */ 1365 laser_data->dist = 0; 1366 laser_data->distmax = (fixed_t) sqrtf((float)((x * x) + (y * y) + (z * z))); 1367 1368 laser_data->next = NULL; 1369 1370 P_LaserCrossBSP(numnodes-1, laser_data); 1371 1372 /* setup laser puff */ 1373 laser = (laser_t *)Z_Malloc( sizeof(*laser), PU_LEVSPEC, 0); 1374 P_AddThinker (&laser->thinker); 1375 laser->thinker.function = T_LaserThinker; 1376 laser->laserdata = laser_data; 1377 laser->marker = P_SpawnMobj(x2, y2, z2, MT_PROJ_LASER); 1378 1379 player->ammo[weaponinfo[player->readyweapon].ammo]--; 1380 1381 if(!linetarget) 1382 { 1383 angleoffs += spread; 1384 } 1385 else 1386 { 1387 damage = ((P_Random() & 7) * 10) + 10; 1388 P_DamageMobj(linetarget, mobj, mobj, damage); 1389 } 1390 } 1391 1392 P_SetPsprite(player, ps_flashalpha, weaponinfo[player->readyweapon].flashstate); 1393 S_StartSound(player->mo, sfx_laser); 1394 }