A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 851 lines 23 kB view raw
1/* Emacs style mode select -*- C++ -*- 2 *----------------------------------------------------------------------------- 3 * 4 * 5 * PrBoom a Doom port merged with LxDoom and LSDLDoom 6 * based on BOOM, a modified and improved DOOM engine 7 * Copyright (C) 1999 by 8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman 9 * Copyright (C) 1999-2000 by 10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 25 * 02111-1307, USA. 26 * 27 * DESCRIPTION: 28 * Weapon sprite animation, weapon objects. 29 * Action functions for weapons. 30 * 31 *-----------------------------------------------------------------------------*/ 32 33#include "doomstat.h" 34#include "r_main.h" 35#include "p_map.h" 36#include "p_inter.h" 37#include "p_pspr.h" 38#include "p_enemy.h" 39#include "m_random.h" 40#include "s_sound.h" 41#include "sounds.h" 42#include "d_event.h" 43#include "rockmacros.h" 44#define LOWERSPEED (FRACUNIT*6) 45#define RAISESPEED (FRACUNIT*6) 46#define WEAPONBOTTOM (FRACUNIT*128) 47#define WEAPONTOP (FRACUNIT*32) 48 49#define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */ 50 51extern void P_Thrust(player_t *, angle_t, fixed_t); 52 53// The following array holds the recoil values // phares 54 55static const int recoil_values[] = { // phares 56 10, // wp_fist 57 10, // wp_pistol 58 30, // wp_shotgun 59 10, // wp_chaingun 60 100,// wp_missile 61 20, // wp_plasma 62 100,// wp_bfg 63 0, // wp_chainsaw 64 80 // wp_supershotgun 65 }; 66 67// 68// P_SetPsprite 69// 70 71static void P_SetPsprite(player_t *player, int position, statenum_t stnum) 72{ 73 pspdef_t *psp = &player->psprites[position]; 74 75 do 76 { 77 state_t *state; 78 79 if (!stnum) 80 { 81 // object removed itself 82 psp->state = NULL; 83 break; 84 } 85 86 state = &states[stnum]; 87 psp->state = state; 88 psp->tics = state->tics; // could be 0 89 90 if (state->misc1) 91 { 92 // coordinate set 93 psp->sx = state->misc1 << FRACBITS; 94 psp->sy = state->misc2 << FRACBITS; 95 } 96 97 // Call action routine. 98 // Modified handling. 99 if (state->action) 100 { 101 state->action(player, psp); 102 if (!psp->state) 103 break; 104 } 105 stnum = psp->state->nextstate; 106 } 107 while (!psp->tics); // an initial state of 0 could cycle through 108} 109 110// 111// P_BringUpWeapon 112// Starts bringing the pending weapon up 113// from the bottom of the screen. 114// Uses player 115// 116 117static void P_BringUpWeapon(player_t *player) 118{ 119 statenum_t newstate; 120 121 if (player->pendingweapon == wp_nochange) 122 player->pendingweapon = player->readyweapon; 123 124 if (player->pendingweapon == wp_chainsaw) 125 S_StartSound (player->mo, sfx_sawup); 126 127 newstate = weaponinfo[player->pendingweapon].upstate; 128 129 player->pendingweapon = wp_nochange; 130 // killough 12/98: prevent pistol from starting visibly at bottom of screen: 131 player->psprites[ps_weapon].sy = 132 mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM; 133 134 P_SetPsprite(player, ps_weapon, newstate); 135} 136 137// The first set is where the weapon preferences from // killough, 138// default.cfg are stored. These values represent the keys used // phares 139// in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // | 140// are NOT the wp_* constants. // V 141 142int weapon_preferences[2][NUMWEAPONS+1] = { 143 {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences 144 {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences 145 }; 146 147// P_SwitchWeapon checks current ammo levels and gives you the 148// most preferred weapon with ammo. It will not pick the currently 149// raised weapon. When called from P_CheckAmmo this won't matter, 150// because the raised weapon has no ammo anyway. When called from 151// G_BuildTiccmd you want to toggle to a different weapon regardless. 152 153int P_SwitchWeapon(player_t *player) 154{ 155 int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98 156 int currentweapon = player->readyweapon; 157 int newweapon = currentweapon; 158 int i = NUMWEAPONS+1; // killough 5/2/98 159 160 // killough 2/8/98: follow preferences and fix BFG/SSG bugs 161 162 do 163 switch (*prefer++) 164 { 165 case 1: 166 if (!player->powers[pw_strength]) // allow chainsaw override 167 break; 168 case 0: 169 newweapon = wp_fist; 170 break; 171 case 2: 172 if (player->ammo[am_clip]) 173 newweapon = wp_pistol; 174 break; 175 case 3: 176 if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) 177 newweapon = wp_shotgun; 178 break; 179 case 4: 180 if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) 181 newweapon = wp_chaingun; 182 break; 183 case 5: 184 if (player->weaponowned[wp_missile] && player->ammo[am_misl]) 185 newweapon = wp_missile; 186 break; 187 case 6: 188 if (player->weaponowned[wp_plasma] && player->ammo[am_cell] && 189 gamemode != shareware) 190 newweapon = wp_plasma; 191 break; 192 case 7: 193 if (player->weaponowned[wp_bfg] && gamemode != shareware && 194 player->ammo[am_cell] >= (demo_compatibility ? 41 : 40)) 195 newweapon = wp_bfg; 196 break; 197 case 8: 198 if (player->weaponowned[wp_chainsaw]) 199 newweapon = wp_chainsaw; 200 break; 201 case 9: 202 if (player->weaponowned[wp_supershotgun] && gamemode == commercial && 203 player->ammo[am_shell] >= (demo_compatibility ? 3 : 2)) 204 newweapon = wp_supershotgun; 205 break; 206 } 207 while (newweapon==currentweapon && --i); // killough 5/2/98 208 return newweapon; 209} 210 211// killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2. 212int P_WeaponPreferred(int w1, int w2) 213{ 214 return 215 (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 || 216 (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 || 217 (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 || 218 (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 || 219 (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 || 220 (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 || 221 (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 || 222 (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1 223 )))))))))))))))); 224} 225 226// 227// P_CheckAmmo 228// Returns true if there is enough ammo to shoot. 229// If not, selects the next weapon to use. 230// (only in demo_compatibility mode -- killough 3/22/98) 231// 232 233boolean P_CheckAmmo(player_t *player) 234{ 235 ammotype_t ammo = weaponinfo[player->readyweapon].ammo; 236 int count = 1; // Regular 237 238 if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies. 239 count = BFGCELLS; 240 else 241 if (player->readyweapon == wp_supershotgun) // Double barrel. 242 count = 2; 243 244 // Some do not need ammunition anyway. 245 // Return if current ammunition sufficient. 246 247 if (ammo == am_noammo || player->ammo[ammo] >= count) 248 return true; 249 250 // Out of ammo, pick a weapon to change to. 251 // 252 // killough 3/22/98: for old demos we do the switch here and now; 253 // for Boom games we cannot do this, and have different player 254 // preferences across demos or networks, so we have to use the 255 // G_BuildTiccmd() interface instead of making the switch here. 256 257 if (demo_compatibility) 258 { 259 player->pendingweapon = P_SwitchWeapon(player); // phares 260 // Now set appropriate weapon overlay. 261 P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); 262 } 263 264 return false; 265} 266 267// 268// P_FireWeapon. 269// 270 271int lastshottic; // killough 3/22/98 272 273static void P_FireWeapon(player_t *player) 274{ 275 statenum_t newstate; 276 277 if (!P_CheckAmmo(player)) 278 return; 279 280 P_SetMobjState(player->mo, S_PLAY_ATK1); 281 newstate = weaponinfo[player->readyweapon].atkstate; 282 P_SetPsprite(player, ps_weapon, newstate); 283 P_NoiseAlert(player->mo, player->mo); 284 lastshottic = gametic; // killough 3/22/98 285} 286 287// 288// P_DropWeapon 289// Player died, so put the weapon away. 290// 291 292void P_DropWeapon(player_t *player) 293{ 294 P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate); 295} 296 297// 298// A_WeaponReady 299// The player can fire the weapon 300// or change to another weapon at this time. 301// Follows after getting weapon up, 302// or after previous attack/fire sequence. 303// 304 305void A_WeaponReady(player_t *player, pspdef_t *psp) 306{ 307 // get out of attack state 308 if (player->mo->state == &states[S_PLAY_ATK1] 309 || player->mo->state == &states[S_PLAY_ATK2] ) 310 P_SetMobjState(player->mo, S_PLAY); 311 312 if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW]) 313 S_StartSound(player->mo, sfx_sawidl); 314 315 // check for change 316 // if player is dead, put the weapon away 317 318 if (player->pendingweapon != wp_nochange || !player->health) 319 { 320 // change weapon (pending weapon should already be validated) 321 statenum_t newstate = weaponinfo[player->readyweapon].downstate; 322 P_SetPsprite(player, ps_weapon, newstate); 323 return; 324 } 325 326 // check for fire 327 // the missile launcher and bfg do not auto fire 328 329 if (player->cmd.buttons & BT_ATTACK) 330 { 331 if (!player->attackdown || (player->readyweapon != wp_missile && 332 player->readyweapon != wp_bfg)) 333 { 334 player->attackdown = true; 335 P_FireWeapon(player); 336 return; 337 } 338 } 339 else 340 player->attackdown = false; 341 342 // bob the weapon based on movement speed 343 { 344 int angle = (128*leveltime) & FINEMASK; 345 psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); 346 angle &= FINEANGLES/2-1; 347 psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); 348 } 349} 350 351// 352// A_ReFire 353// The player can re-fire the weapon 354// without lowering it entirely. 355// 356 357void A_ReFire(player_t *player, pspdef_t *psp) 358{ 359 (void)psp; 360 // check for fire 361 // (if a weaponchange is pending, let it go through instead) 362 363 if ( (player->cmd.buttons & BT_ATTACK) 364 && player->pendingweapon == wp_nochange && player->health) 365 { 366 player->refire++; 367 P_FireWeapon(player); 368 } 369 else 370 { 371 player->refire = 0; 372 P_CheckAmmo(player); 373 } 374} 375 376void A_CheckReload(player_t *player, pspdef_t *psp) 377{ 378 (void)psp; 379 P_CheckAmmo(player); 380} 381 382// 383// A_Lower 384// Lowers current weapon, 385// and changes weapon at bottom. 386// 387 388void A_Lower(player_t *player, pspdef_t *psp) 389{ 390 psp->sy += LOWERSPEED; 391 392 // Is already down. 393 if (psp->sy < WEAPONBOTTOM) 394 return; 395 396 // Player is dead. 397 if (player->playerstate == PST_DEAD) 398 { 399 psp->sy = WEAPONBOTTOM; 400 return; // don't bring weapon back up 401 } 402 403 // The old weapon has been lowered off the screen, 404 // so change the weapon and start raising it 405 406 if (!player->health) 407 { // Player is dead, so keep the weapon off screen. 408 P_SetPsprite(player, ps_weapon, S_NULL); 409 return; 410 } 411 412 player->readyweapon = player->pendingweapon; 413 414 P_BringUpWeapon(player); 415} 416 417// 418// A_Raise 419// 420 421void A_Raise(player_t *player, pspdef_t *psp) 422{ 423 statenum_t newstate; 424 425 psp->sy -= RAISESPEED; 426 427 if (psp->sy > WEAPONTOP) 428 return; 429 430 psp->sy = WEAPONTOP; 431 432 // The weapon has been raised all the way, 433 // so change to the ready state. 434 435 newstate = weaponinfo[player->readyweapon].readystate; 436 437 P_SetPsprite(player, ps_weapon, newstate); 438} 439 440 441// Weapons now recoil, amount depending on the weapon. // phares 442// // | 443// The P_SetPsprite call in each of the weapon firing routines // V 444// was moved here so the recoil could be synched with the 445// muzzle flash, rather than the pressing of the trigger. 446// The BFG delay caused this to be necessary. 447 448static void A_FireSomething(player_t* player,int adder) 449{ 450 P_SetPsprite(player, ps_flash, 451 weaponinfo[player->readyweapon].flashstate+adder); 452 453 // killough 3/27/98: prevent recoil in no-clipping mode 454 if (!(player->mo->flags & MF_NOCLIP)) 455 if (!compatibility && weapon_recoil) 456 P_Thrust(player, 457 ANG180+player->mo->angle, // ^ 458 2048*recoil_values[player->readyweapon]); // | 459} // phares 460 461// 462// A_GunFlash 463// 464 465void A_GunFlash(player_t *player, pspdef_t *psp) 466{ 467 (void)psp; 468 P_SetMobjState(player->mo, S_PLAY_ATK2); 469 470 A_FireSomething(player,0); // phares 471} 472 473// 474// WEAPON ATTACKS 475// 476 477// 478// A_Punch 479// 480 481void A_Punch(player_t *player, pspdef_t *psp) 482{ 483 (void)psp; 484 angle_t angle; 485 int t, slope, damage = (P_Random(pr_punch)%10+1)<<1; 486 487 if (player->powers[pw_strength]) 488 damage *= 10; 489 490 angle = player->mo->angle; 491 492 // killough 5/5/98: remove dependence on order of evaluation: 493 t = P_Random(pr_punchangle); 494 angle += (t - P_Random(pr_punchangle))<<18; 495 496 /* killough 8/2/98: make autoaiming prefer enemies */ 497 if (!mbf_features || 498 (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND), 499 !linetarget)) 500 slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0); 501 502 P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); 503 504 if (!linetarget) 505 return; 506 507 S_StartSound(player->mo, sfx_punch); 508 509 // turn to face target 510 511 player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, 512 linetarget->x, linetarget->y); 513} 514 515// 516// A_Saw 517// 518 519void A_Saw(player_t *player, pspdef_t *psp) 520{ 521 (void)psp; 522 int slope, damage = 2*(P_Random(pr_saw)%10+1); 523 angle_t angle = player->mo->angle; 524 // killough 5/5/98: remove dependence on order of evaluation: 525 int t = P_Random(pr_saw); 526 angle += (t - P_Random(pr_saw))<<18; 527 528 /* Use meleerange + 1 so that the puff doesn't skip the flash 529 * killough 8/2/98: make autoaiming prefer enemies */ 530 if (!mbf_features || 531 (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND), 532 !linetarget)) 533 slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0); 534 535 P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage); 536 537 if (!linetarget) 538 { 539 S_StartSound(player->mo, sfx_sawful); 540 return; 541 } 542 543 S_StartSound(player->mo, sfx_sawhit); 544 545 // turn to face target 546 angle = R_PointToAngle2(player->mo->x, player->mo->y, 547 linetarget->x, linetarget->y); 548 549 if (angle - player->mo->angle > ANG180) { 550 if (angle - player->mo->angle < (unsigned)(-ANG90/20)) 551 player->mo->angle = angle + ANG90/21; 552 else 553 player->mo->angle -= ANG90/20; 554 } else { 555 if (angle - player->mo->angle > ANG90/20) 556 player->mo->angle = angle - ANG90/21; 557 else 558 player->mo->angle += ANG90/20; 559 } 560 561 player->mo->flags |= MF_JUSTATTACKED; 562} 563 564// 565// A_FireMissile 566// 567 568void A_FireMissile(player_t *player, pspdef_t *psp) 569{ 570 (void)psp; 571 player->ammo[weaponinfo[player->readyweapon].ammo]--; 572 P_SpawnPlayerMissile(player->mo, MT_ROCKET); 573} 574 575// 576// A_FireBFG 577// 578 579void A_FireBFG(player_t *player, pspdef_t *psp) 580{ 581 (void)psp; 582 player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; 583 P_SpawnPlayerMissile(player->mo, MT_BFG); 584} 585 586/* 587 * A_FireOldBFG 588 * 589 * This function emulates Doom's Pre-Beta BFG 590 * By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 591 * 592 * This code may not be used in other mods without appropriate credit given. 593 * Code leeches will be telefragged. 594 */ 595 596void A_FireOldBFG(player_t *player, pspdef_t *psp) 597{ 598 (void)psp; 599 (void)player; 600} 601 602// 603// A_FirePlasma 604// 605 606void A_FirePlasma(player_t *player, pspdef_t *psp) 607{ 608 (void)psp; 609 player->ammo[weaponinfo[player->readyweapon].ammo]--; 610 611 A_FireSomething(player,P_Random(pr_plasma)&1); // phares 612 P_SpawnPlayerMissile(player->mo, MT_PLASMA); 613} 614 615// 616// P_BulletSlope 617// Sets a slope so a near miss is at aproximately 618// the height of the intended target 619// 620 621static fixed_t bulletslope; 622 623static void P_BulletSlope(mobj_t *mo) 624{ 625 angle_t an = mo->angle; // see which target is to be aimed at 626 627 /* killough 8/2/98: make autoaiming prefer enemies */ 628 uint_64_t mask = mbf_features ? MF_FRIEND : 0; 629 630 do 631 { 632 bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask); 633 if (!linetarget) 634 bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask); 635 if (!linetarget) 636 bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask); 637 } 638 while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */ 639} 640 641// 642// P_GunShot 643// 644 645void P_GunShot(mobj_t *mo, boolean accurate) 646{ 647 int damage = 5*(P_Random(pr_gunshot)%3+1); 648 angle_t angle = mo->angle; 649 650 if (!accurate) 651 { // killough 5/5/98: remove dependence on order of evaluation: 652 int t = P_Random(pr_misfire); 653 angle += (t - P_Random(pr_misfire))<<18; 654 } 655 656 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); 657} 658 659// 660// A_FirePistol 661// 662 663void A_FirePistol(player_t *player, pspdef_t *psp) 664{ 665 (void)psp; 666 S_StartSound(player->mo, sfx_pistol); 667 668 P_SetMobjState(player->mo, S_PLAY_ATK2); 669 player->ammo[weaponinfo[player->readyweapon].ammo]--; 670 671 A_FireSomething(player,0); // phares 672 P_BulletSlope(player->mo); 673 P_GunShot(player->mo, !player->refire); 674} 675 676// 677// A_FireShotgun 678// 679 680void A_FireShotgun(player_t *player, pspdef_t *psp) 681{ 682 (void)psp; 683 int i; 684 685 S_StartSound(player->mo, sfx_shotgn); 686 P_SetMobjState(player->mo, S_PLAY_ATK2); 687 688 player->ammo[weaponinfo[player->readyweapon].ammo]--; 689 690 A_FireSomething(player,0); // phares 691 692 P_BulletSlope(player->mo); 693 694 for (i=0; i<7; i++) 695 P_GunShot(player->mo, false); 696} 697 698// 699// A_FireShotgun2 700// 701 702void A_FireShotgun2(player_t *player, pspdef_t *psp) 703{ 704 (void)psp; 705 int i; 706 707 S_StartSound(player->mo, sfx_dshtgn); 708 P_SetMobjState(player->mo, S_PLAY_ATK2); 709 player->ammo[weaponinfo[player->readyweapon].ammo] -= 2; 710 711 A_FireSomething(player,0); // phares 712 713 P_BulletSlope(player->mo); 714 715 for (i=0; i<20; i++) 716 { 717 int damage = 5*(P_Random(pr_shotgun)%3+1); 718 angle_t angle = player->mo->angle; 719 // killough 5/5/98: remove dependence on order of evaluation: 720 int t = P_Random(pr_shotgun); 721 angle += (t - P_Random(pr_shotgun))<<19; 722 t = P_Random(pr_shotgun); 723 P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope + 724 ((t - P_Random(pr_shotgun))<<5), damage); 725 } 726} 727 728// 729// A_FireCGun 730// 731 732void A_FireCGun(player_t *player, pspdef_t *psp) 733{ 734 if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound]) 735 S_StartSound(player->mo, sfx_pistol); 736 737 if (!player->ammo[weaponinfo[player->readyweapon].ammo]) 738 return; 739 740 P_SetMobjState(player->mo, S_PLAY_ATK2); 741 player->ammo[weaponinfo[player->readyweapon].ammo]--; 742 743 A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares 744 745 P_BulletSlope(player->mo); 746 747 P_GunShot(player->mo, !player->refire); 748} 749 750void A_Light0(player_t *player, pspdef_t *psp) 751{ 752 (void)psp; 753 player->extralight = 0; 754} 755 756void A_Light1 (player_t *player, pspdef_t *psp) 757{ 758 (void)psp; 759 player->extralight = 1; 760} 761 762void A_Light2 (player_t *player, pspdef_t *psp) 763{ 764 (void)psp; 765 player->extralight = 2; 766} 767 768// 769// A_BFGSpray 770// Spawn a BFG explosion on every monster in view 771// 772 773void A_BFGSpray(mobj_t *mo) 774{ 775 int i; 776 777 for (i=0 ; i<40 ; i++) // offset angles from its attack angle 778 { 779 int j, damage; 780 angle_t an = mo->angle - ANG90/2 + ANG90/40*i; 781 782 // mo->target is the originator (player) of the missile 783 784 // killough 8/2/98: make autoaiming prefer enemies 785 if (!mbf_features || 786 (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND), 787 !linetarget)) 788 P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0); 789 790 if (!linetarget) 791 continue; 792 793 P_SpawnMobj(linetarget->x, linetarget->y, 794 linetarget->z + (linetarget->height>>2), MT_EXTRABFG); 795 796 for (damage=j=0; j<15; j++) 797 damage += (P_Random(pr_bfg)&7) + 1; 798 799 P_DamageMobj(linetarget, mo->target, mo->target, damage); 800 } 801} 802 803// 804// A_BFGsound 805// 806 807void A_BFGsound(player_t *player, pspdef_t *psp) 808{ 809 (void)psp; 810 S_StartSound(player->mo, sfx_bfg); 811} 812 813// 814// P_SetupPsprites 815// Called at start of level for each player. 816// 817 818void P_SetupPsprites(player_t *player) 819{ 820 int i; 821 822 // remove all psprites 823 for (i=0; i<NUMPSPRITES; i++) 824 player->psprites[i].state = NULL; 825 826 // spawn the gun 827 player->pendingweapon = player->readyweapon; 828 P_BringUpWeapon(player); 829} 830 831// 832// P_MovePsprites 833// Called every tic by player thinking routine. 834// 835 836void P_MovePsprites(player_t *player) 837{ 838 pspdef_t *psp = player->psprites; 839 int i; 840 841 // a null state means not active 842 // drop tic count and possibly change state 843 // a -1 tic count never changes 844 845 for (i=0; i<NUMPSPRITES; i++, psp++) 846 if (psp->state && psp->tics != -1 && !--psp->tics) 847 P_SetPsprite(player, i, psp->state->nextstate); 848 849 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; 850 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; 851}